/**************************************************************************
 *                                                                        *
 *               Copyright (C) 1994, Silicon Graphics, Inc.               *
 *                                                                        *
 *  These coded instructions, statements, and computer programs  contain  *
 *  unpublished  proprietary  information of Silicon Graphics, Inc., and  *
 *  are protected by Federal copyright law.  They  may  not be disclosed  *
 *  to  third  parties  or copied or duplicated in any form, in whole or  *
 *  in part, without the prior written consent of Silicon Graphics, Inc.  *
 *                                                                        *
 **************************************************************************/
/**************************************************************************
 *
 *  $Revision: 1.138 $
 *  $Date: 1998/12/24 09:05:08 $
 *  $Source: /hosts/gate3/exdisk2/cvs/N64OS/Master/cvsmdev2/PR/include/gbi.h,v $
 *
 **************************************************************************/

#ifndef _GBI_H_
#define _GBI_H_

#include <PR/ultratypes.h>
#include "gbiex.h"
#include <stdint.h>

#ifndef PLATFORM_N64
#include "platform.h"
#endif


/*
 * To use the F3DEX ucodes, define F3DEX_GBI before include this file.
 *
 *     #define  F3DEX_GBI
 *     #include <ultra64.h>
 *
 *     or
 *
 *     cc -c -DF3DEX_GBI -I.... foo.c
 *
 */

/**************************************************************************
 *
 * Graphics Binary Interface
 *
 **************************************************************************/

/*
 * Graphics Commands, 'xxx' parts may be generated from ucode
 *
 * The command format is
 *
 *  |00xxxxxx| = DMA            0,..,127
 *  |10xxxxxx| = Immediate Mode -65,..,-128
 *  |11xxxxxx| = RDP cmds       -1,..,-64
 *
 * Note: in order for the RSP microcode to process RDP commands opaquely,
 * we need to further identify those RDP commands that need DRAM address
 * "fixup". To do this, we have the dummy command G_RDP_ADDR_FIXUP, and
 * all |RDP commands| less than this are commands with embedded DRAM
 * addresses. Further, the format of these commands should be similar so
 * only one fixup routine is needed.
 *
 * Further explanation:
 * The names of the commands are somewhat misleading. Here is clarification:
 *
 *  - a 'DMA' type command has a pointer to additional data and
 *    causes a DMA transfer to bring that into DMEM.
 *
 *  - an 'Immediate' type command isn't really 'immediate', in the
 *    traditional sense. This just means that the entire command fits
 *    in the 64-bit word, and the ucode can execute it 'immediately'
 *    without additional memory transfers.
 *
 *  - an 'RDP' command is identified as such because the RDP
 *    commands can be passed-thru the RSP and sent to the RDP
 *    directly. One further confusing thing, is that some 'DP'
 *    macros below actually generate immediate commands, not
 *    not direct DP commands.
 *
 * IMPLEMENTATION NOTE:
 * There is another group of RDP commands that includes the triangle commands
 * generated by the RSP code. These are the raw commands the rasterizer
 * hardware chews on, with slope info, etc. They will follow the RDP
 * ordering...
 *
 * IMPLEMENTATION NOTE:
 * The RDP hardware has some of these bit patterns wired up. If the hardware
 * changes, we must adjust this table, likewise we can't change/add things
 * once the hardware is frozen. (actually, the RDP hardware only looks at
 * the lower 6 bits of the command byte)
 *
 */

/* DMA commands: */
#define G_SPNOOP        0 /* handle 0 gracefully */
#define G_MTX           1
#define G_RESERVED0     2 /* not implemeted */
#define G_MOVEMEM       3 /* move a block of memory (up to 4 words) to dmem */
#define G_VTX           4
#define G_RESERVED1     5 /* not implemeted */
#define G_DL            6
#define G_COL           7 /* new in PD */
#define G_RESERVED3     8 /* not implemeted */
#define G_SPRITE2D_BASE 9 /* sprite command */

/* IMMEDIATE commands: */
#define G_IMMFIRST          -65
#define G_TRI1              (G_IMMFIRST-0)   /* -65 / 0xbf */
#define G_CULLDL            0                /* -66 / 0xbe */
#define G_POPMTX            0                /* -67 / 0xbd */
#define G_MOVEWORD          (G_IMMFIRST-3)   /* -68 / 0xbc */
#define G_TEXTURE           (G_IMMFIRST-4)   /* -69 / 0xbb */
#define G_SETOTHERMODE_H    (G_IMMFIRST-5)   /* -70 / 0xba */
#define G_SETOTHERMODE_L    (G_IMMFIRST-6)   /* -71 / 0xb9 */
#define G_ENDDL             (G_IMMFIRST-7)   /* -72 / 0xb8 */
#define G_SETGEOMETRYMODE   (G_IMMFIRST-8)   /* -73 / 0xb7 */
#define G_CLEARGEOMETRYMODE (G_IMMFIRST-9)   /* -74 / 0xb6 */
#define G_LINE3D            (G_IMMFIRST-10)  /* -75 / 0xb5 */
#define G_RDPHALF_1         (G_IMMFIRST-11)  /* -76 / 0xb4 */
#define G_RDPHALF_2         (G_IMMFIRST-12)  /* -77 / 0xb3 */
#define G_RDPHALF_CONT      (G_IMMFIRST-13)  /* -78 / 0xb2 */
#define G_TRI4              (G_IMMFIRST-14)  /* -79 / 0xb1 */

/* We are overloading 2 of the immediate commands
   to keep the byte alignment of dmem the same */

#define G_SPRITE2D_SCALEFLIP (G_IMMFIRST-1)
#define G_SPRITE2D_DRAW      (G_IMMFIRST-2)

/* RDP commands: */
#define G_NOOP            0xc0 /*   0 */

/* RDP commands: */
#define G_SETCIMG         0xff /* -1  */
#define G_SETZIMG         0xfe /* -2  */
#define G_SETTIMG         0xfd /* -3  */
#define G_SETCOMBINE      0xfc /* -4  */
#define G_SETENVCOLOR     0xfb /* -5  */
#define G_SETPRIMCOLOR    0xfa /* -6  */
#define G_SETBLENDCOLOR   0xf9 /* -7  */
#define G_SETFOGCOLOR     0xf8 /* -8  */
#define G_SETFILLCOLOR    0xf7 /* -9  */
#define G_FILLRECT        0xf6 /* -10 */
#define G_SETTILE         0xf5 /* -11 */
#define G_LOADTILE        0xf4 /* -12 */
#define G_LOADBLOCK       0xf3 /* -13 */
#define G_SETTILESIZE     0xf2 /* -14 */
#define G_LOADTLUT        0xf0 /* -16 */
#define G_RDPSETOTHERMODE 0xef /* -17 */
#define G_SETPRIMDEPTH    0xee /* -18 */
#define G_SETSCISSOR      0xed /* -19 */
#define G_SETCONVERT      0xec /* -20 */
#define G_SETKEYR         0xeb /* -21 */
#define G_SETKEYGB        0xea /* -22 */
#define G_RDPFULLSYNC     0xe9 /* -23 */
#define G_RDPTILESYNC     0xe8 /* -24 */
#define G_RDPPIPESYNC     0xe7 /* -25 */
#define G_RDPLOADSYNC     0xe6 /* -26 */
#define G_TEXRECTFLIP     0xe5 /* -27 */
#define G_TEXRECT         0xe4 /* -28 */


/*
 * The following commands are the "generated" RDP commands; the user
 * never sees them, the RSP microcode generates them.
 *
 * The layout of the bits is magical, to save work in the ucode.
 * These id's are -56, -52, -54, -50, -55, -51, -53, -49, ...
 *                                 edge, shade, texture, zbuff bits:  estz
 */
#define G_TRI_FILL             0xc8 /* fill triangle:            11001000 */
#define G_TRI_SHADE            0xcc /* shade triangle:           11001100 */
#define G_TRI_TXTR             0xca /* texture triangle:         11001010 */
#define G_TRI_SHADE_TXTR       0xce /* shade, texture triangle:  11001110 */
#define G_TRI_FILL_ZBUFF       0xc9 /* fill, zbuff triangle:     11001001 */
#define G_TRI_SHADE_ZBUFF      0xcd /* shade, zbuff triangle:    11001101 */
#define G_TRI_TXTR_ZBUFF       0xcb /* texture, zbuff triangle:  11001011 */
#define G_TRI_SHADE_TXTR_ZBUFF 0xcf /* shade, txtr, zbuff trngl: 11001111 */

/*
 * A TRI_FILL triangle is just the edges. You need to set the DP
 * to use primcolor, in order to see anything. (it is NOT a triangle
 * that gets rendered in 'fill mode'. Triangles can't be rendered
 * in 'fill mode')
 *
 * A TRI_SHADE is a gouraud triangle that has colors interpolated.
 * Flat-shaded triangles (from the software) are still gouraud shaded,
 * it's just the colors are all the same and the deltas are 0.
 *
 * Other triangle types, and combinations are more obvious.
 */

/* masks to build RDP triangle commands: */
#define G_RDP_TRI_FILL_MASK  0x08
#define G_RDP_TRI_SHADE_MASK 0x04
#define G_RDP_TRI_TXTR_MASK  0x02
#define G_RDP_TRI_ZBUFF_MASK 0x01

/* gets added to RDP command, in order to test for addres fixup: */
#define G_RDP_ADDR_FIXUP  3 /* |RDP cmds| <= this, do addr fixup */

#ifdef _LANGUAGE_ASSEMBLY
#define G_RDP_TEXRECT_CHECK ((-1*G_TEXRECTFLIP)& 0xff)
#endif

/* macros for command parsing: */
#define GDMACMD(x) (x)
#define GIMMCMD(x) (G_IMMFIRST-(x))
#define GRDPCMD(x) (0xff-(x))

#define G_DMACMDSIZ 128
#define G_IMMCMDSIZ 64
#define G_RDPCMDSIZ 64

/*
 * Coordinate shift values, number of bits of fraction
 */
#define G_TEXTURE_IMAGE_FRAC 2
#define G_TEXTURE_SCALE_FRAC 16
#define G_SCALE_FRAC         8
#define G_ROTATE_FRAC        16

/*
 * Parameters to graphics commands
 */

/*
 * Data packing macros
 */

/*
 * Maximum z-buffer value, used to initialize the z-buffer.
 * Note : this number is NOT the viewport z-scale constant.
 * See the comment next to G_MAXZ for more info.
 */
#define G_MAXFBZ 0x3fff /* 3b exp, 11b mantissa */

#define GPACK_RGBA5551(r, g, b, a) ((((r)<<8) & 0xf800) | \
        (((g)<<3) & 0x7c0) |                              \
        (((b)>>2) & 0x3e) | ((a) & 0x1))

#define GPACK_ZDZ(z, dz) ((z) << 2 | (dz))

/*
 * G_MTX: parameter flags
 */
#define G_MTX_MODELVIEW  0x00 /* matrix types */
#define G_MTX_PROJECTION 0x01
#define G_MTX_MUL        0x00 /* concat or load */
#define G_MTX_LOAD       0x02
#define G_MTX_NOPUSH     0x00 /* push or not */
#define G_MTX_PUSH       0x04

/*
 * flags for G_SETGEOMETRYMODE
 * (this rendering state is maintained in RSP)
 *
 * DO NOT USE THE LOW 8 BITS OF GEOMETRYMODE:
 * The weird bit-ordering is for the micro-code: the lower byte
 * can be OR'd in with G_TRI_SHADE (11001100) to construct
 * the triangle command directly. Don't break it...
 *
 * DO NOT USE THE HIGH 8 BITS OF GEOMETRYMODE:
 * The high byte is OR'd with 0x703 to form the clip code mask.
 * If it is set to 0x04, this will cause near clipping to occur.
 * If it is zero, near clipping will not occur.
 *
 * Further explanation:
 * G_SHADE is necessary in order to see the color that you passed
 * down with the vertex. If G_SHADE isn't set, you need to set the DP
 * appropriately and use primcolor to see anything.
 *
 * G_SHADING_SMOOTH enabled means use all 3 colors of the triangle.
 * If it is not set, then do 'flat shading', where only one vertex color
 * is used (and all 3 vertices are set to that same color by the ucode)
 * See the man page for gSP1Triangle().
 *
 */
#define G_ZBUFFER            0x00000001
#define G_SHADE              0x00000004 /* enable Gouraud interp */
/* rest of low byte reserved for setup ucode */
#define G_TEXTURE_ENABLE     0x00000002 /* Microcode use only */
#define G_SHADING_SMOOTH     0x00000200 /* flat or smooth shaded */
#define G_CULL_FRONT         0x00001000
#define G_CULL_BACK          0x00002000
#define G_CULL_BOTH          0x00003000 /* To make code cleaner */
#define G_FOG                0x00010000
#define G_LIGHTING           0x00020000
#define G_TEXTURE_GEN        0x00040000
#define G_TEXTURE_GEN_LINEAR 0x00080000
#define G_LOD                0x00100000 /* NOT IMPLEMENTED */
#define G_CLIPPING           0x00000000

#ifdef _LANGUAGE_ASSEMBLY
#define G_FOG_H                (G_FOG/0x10000)
#define G_LIGHTING_H           (G_LIGHTING/0x10000)
#define G_TEXTURE_GEN_H        (G_TEXTURE_GEN/0x10000)
#define G_TEXTURE_GEN_LINEAR_H (G_TEXTURE_GEN_LINEAR/0x10000)
#define G_LOD_H                (G_LOD/0x10000) /* NOT IMPLEMENTED */
#endif

/* Need these defined for Sprite Microcode */
#ifdef _LANGUAGE_ASSEMBLY
#define G_TX_LOADTILE   7
#define G_TX_RENDERTILE 0
#define G_TX_NOMIRROR   0
#define G_TX_WRAP       0
#define G_TX_MIRROR     1
#define G_TX_CLAMP      2
#define G_TX_NOMASK     0
#define G_TX_NOLOD      0
#endif

/*
 * G_SETIMG fmt: set image formats
 */
#define G_IM_FMT_RGBA 0
#define G_IM_FMT_YUV  1
#define G_IM_FMT_CI   2
#define G_IM_FMT_IA   3
#define G_IM_FMT_I    4

/*
 * G_SETIMG siz: set image pixel size
 */
#define G_IM_SIZ_4b  0
#define G_IM_SIZ_8b  1
#define G_IM_SIZ_16b 2
#define G_IM_SIZ_32b 3
#define G_IM_SIZ_DD  5

#define G_IM_SIZ_4b_BYTES       0
#define G_IM_SIZ_4b_TILE_BYTES  G_IM_SIZ_4b_BYTES
#define G_IM_SIZ_4b_LINE_BYTES  G_IM_SIZ_4b_BYTES

#define G_IM_SIZ_8b_BYTES       1
#define G_IM_SIZ_8b_TILE_BYTES  G_IM_SIZ_8b_BYTES
#define G_IM_SIZ_8b_LINE_BYTES  G_IM_SIZ_8b_BYTES

#define G_IM_SIZ_16b_BYTES      2
#define G_IM_SIZ_16b_TILE_BYTES G_IM_SIZ_16b_BYTES
#define G_IM_SIZ_16b_LINE_BYTES G_IM_SIZ_16b_BYTES

#define G_IM_SIZ_32b_BYTES      4
#define G_IM_SIZ_32b_TILE_BYTES 2
#define G_IM_SIZ_32b_LINE_BYTES 2

#define G_IM_SIZ_4b_LOAD_BLOCK  G_IM_SIZ_16b
#define G_IM_SIZ_8b_LOAD_BLOCK  G_IM_SIZ_16b
#define G_IM_SIZ_16b_LOAD_BLOCK G_IM_SIZ_16b
#define G_IM_SIZ_32b_LOAD_BLOCK G_IM_SIZ_32b

#define G_IM_SIZ_4b_SHIFT  2
#define G_IM_SIZ_8b_SHIFT  1
#define G_IM_SIZ_16b_SHIFT 0
#define G_IM_SIZ_32b_SHIFT 0

#define G_IM_SIZ_4b_INCR  3
#define G_IM_SIZ_8b_INCR  1
#define G_IM_SIZ_16b_INCR 0
#define G_IM_SIZ_32b_INCR 0

/*
 * G_SETCOMBINE: color combine modes
 */
/* Color combiner constants: */
#define G_CCMUX_COMBINED        0
#define G_CCMUX_TEXEL0          1
#define G_CCMUX_TEXEL1          2
#define G_CCMUX_PRIMITIVE       3
#define G_CCMUX_SHADE           4
#define G_CCMUX_ENVIRONMENT     5
#define G_CCMUX_CENTER          6
#define G_CCMUX_SCALE           6
#define G_CCMUX_COMBINED_ALPHA  7
#define G_CCMUX_TEXEL0_ALPHA    8
#define G_CCMUX_TEXEL1_ALPHA    9
#define G_CCMUX_PRIMITIVE_ALPHA 10
#define G_CCMUX_SHADE_ALPHA     11
#define G_CCMUX_ENV_ALPHA       12
#define G_CCMUX_LOD_FRACTION    13
#define G_CCMUX_PRIM_LOD_FRAC   14
#define G_CCMUX_NOISE           7
#define G_CCMUX_K4              7
#define G_CCMUX_K5              15
#define G_CCMUX_1               6
#define G_CCMUX_0               31

/* Alpha combiner constants: */
#define G_ACMUX_COMBINED      0
#define G_ACMUX_TEXEL0        1
#define G_ACMUX_TEXEL1        2
#define G_ACMUX_PRIMITIVE     3
#define G_ACMUX_SHADE         4
#define G_ACMUX_ENVIRONMENT   5
#define G_ACMUX_LOD_FRACTION  0
#define G_ACMUX_PRIM_LOD_FRAC 6
#define G_ACMUX_1             6
#define G_ACMUX_0             7

/* typical CC cycle 1 modes */
#define G_CC_PRIMITIVE              0,                        0,           0,            PRIMITIVE,   0,         0,     0,         PRIMITIVE
#define G_CC_SHADE                  0,                        0,           0,            SHADE,       0,         0,     0,         SHADE
#define G_CC_MODULATEI              TEXEL0,                   0,           SHADE,        0,           0,         0,     0,         SHADE
#define G_CC_MODULATEIA             TEXEL0,                   0,           SHADE,        0,           TEXEL0,    0,     SHADE,     0
#define G_CC_MODULATEIDECALA        TEXEL0,                   0,           SHADE,        0,           0,         0,     0,         TEXEL0
#define G_CC_MODULATERGB            G_CC_MODULATEI
#define G_CC_MODULATERGBA           G_CC_MODULATEIA
#define G_CC_MODULATERGBDECALA      G_CC_MODULATEIDECALA
#define G_CC_MODULATEI_PRIM         TEXEL0,                   0,           PRIMITIVE,    0,           0,         0,     0,         PRIMITIVE
#define G_CC_MODULATEIA_PRIM        TEXEL0,                   0,           PRIMITIVE,    0,           TEXEL0,    0,     PRIMITIVE, 0
#define G_CC_MODULATEIDECALA_PRIM   TEXEL0,                   0,           PRIMITIVE,    0,           0,         0,     0,         TEXEL0
#define G_CC_MODULATERGB_PRIM       G_CC_MODULATEI_PRIM
#define G_CC_MODULATERGBA_PRIM      G_CC_MODULATEIA_PRIM
#define G_CC_MODULATERGBDECALA_PRIM G_CC_MODULATEIDECALA_PRIM
#define G_CC_DECALRGB               0,                        0,           0,            TEXEL0,      0,         0,     0,         SHADE
#define G_CC_DECALRGBA              0,                        0,           0,            TEXEL0,      0,         0,     0,         TEXEL0
#define G_CC_BLENDI                 ENVIRONMENT,              SHADE,       TEXEL0,       SHADE,       0,         0,     0,         SHADE
#define G_CC_BLENDIA                ENVIRONMENT,              SHADE,       TEXEL0,       SHADE,       TEXEL0,    0,     SHADE,     0
#define G_CC_BLENDIDECALA           ENVIRONMENT,              SHADE,       TEXEL0,       SHADE,       0,         0,     0,         TEXEL0
#define G_CC_BLENDRGBA              TEXEL0,                   SHADE,       TEXEL0_ALPHA, SHADE,       0,         0,     0,         SHADE
#define G_CC_BLENDRGBDECALA         TEXEL0,                   SHADE,       TEXEL0_ALPHA, SHADE,       0,         0,     0,         TEXEL0
#define G_CC_ADDRGB                 1,                        0,           TEXEL0,       SHADE,       0,         0,     0,         SHADE
#define G_CC_ADDRGBDECALA           1,                        0,           TEXEL0,       SHADE,       0,         0,     0,         TEXEL0
#define G_CC_REFLECTRGB             ENVIRONMENT,              0,           TEXEL0,       SHADE,       0,         0,     0,         SHADE
#define G_CC_REFLECTRGBDECALA       ENVIRONMENT,              0,           TEXEL0,       SHADE,       0,         0,     0,         TEXEL0
#define G_CC_HILITERGB              PRIMITIVE,                SHADE,       TEXEL0,       SHADE,       0,         0,     0,         SHADE
#define G_CC_HILITERGBA             PRIMITIVE,                SHADE,       TEXEL0,       SHADE,       PRIMITIVE, SHADE, TEXEL0,    SHADE
#define G_CC_HILITERGBDECALA        PRIMITIVE,                SHADE,       TEXEL0,       SHADE,       0,         0,     0,         TEXEL0
#define G_CC_SHADEDECALA            0,                        0,           0,            SHADE,       0,         0,     0,         TEXEL0
#define G_CC_BLENDPE                PRIMITIVE,                ENVIRONMENT, TEXEL0,       ENVIRONMENT, TEXEL0,    0,     SHADE,     0
#define G_CC_BLENDPEDECALA          PRIMITIVE,                ENVIRONMENT, TEXEL0,       ENVIRONMENT, 0,         0,     0,         TEXEL0

/* oddball modes */
#define _G_CC_BLENDPE       ENVIRONMENT, PRIMITIVE, TEXEL0,        PRIMITIVE, TEXEL0,    0,      SHADE,         0
#define _G_CC_BLENDPEDECALA ENVIRONMENT, PRIMITIVE, TEXEL0,        PRIMITIVE, 0,         0,      0,             TEXEL0
#define _G_CC_TWOCOLORTEX   PRIMITIVE,   SHADE,     TEXEL0,        SHADE,     0,         0,      0,             SHADE

/* used for 1-cycle sparse mip-maps, primitive color has color of lowest LOD */
#define _G_CC_SPARSEST      PRIMITIVE,   TEXEL0,    LOD_FRACTION,  TEXEL0,    PRIMITIVE, TEXEL0, LOD_FRACTION,  TEXEL0
#define G_CC_TEMPLERP       TEXEL1,      TEXEL0,    PRIM_LOD_FRAC, TEXEL0,    TEXEL1,    TEXEL0, PRIM_LOD_FRAC, TEXEL0

/* typical CC cycle 1 modes, usually followed by other cycle 2 modes */
#define G_CC_TRILERP        TEXEL1,      TEXEL0,    LOD_FRACTION,  TEXEL0,    TEXEL1,    TEXEL0, LOD_FRACTION,  TEXEL0
#define G_CC_INTERFERENCE   TEXEL0,      0,         TEXEL1,        0,         TEXEL0,    0,      TEXEL1,        0

/*
 *  One-cycle color convert operation
 */
#define G_CC_1CYUV2RGB TEXEL0, K4, K5, TEXEL0, 0, 0, 0, SHADE

/*
 *  NOTE: YUV2RGB expects TF step1 color conversion to occur in 2nd clock.
 * Therefore, CC looks for step1 results in TEXEL1
 */
#define G_CC_YUV2RGB TEXEL1, K4, K5, TEXEL1, 0, 0, 0, 0

/* typical CC cycle 2 modes */
#define G_CC_PASS2              0,                    0,        0,         COMBINED, 0,           0,        0,         COMBINED
#define G_CC_MODULATEI2         COMBINED,             0,        SHADE,     0,        0,           0,        0,         SHADE
#define G_CC_MODULATEIA2        COMBINED,             0,        SHADE,     0,        COMBINED,    0,        SHADE,     0
#define G_CC_MODULATERGB2       G_CC_MODULATEI2
#define G_CC_MODULATERGBA2      G_CC_MODULATEIA2
#define G_CC_MODULATEI_PRIM2    COMBINED,             0,        PRIMITIVE, 0,        0,           0,        0,         PRIMITIVE
#define G_CC_MODULATEIA_PRIM2   COMBINED,             0,        PRIMITIVE, 0,        COMBINED,    0,        PRIMITIVE, 0
#define G_CC_MODULATERGB_PRIM2  G_CC_MODULATEI_PRIM2
#define G_CC_MODULATERGBA_PRIM2 G_CC_MODULATEIA_PRIM2
#define G_CC_DECALRGB2          0,                    0,        0,         COMBINED, 0,           0,        0,         SHADE
#define G_CC_BLENDI2            ENVIRONMENT,          SHADE,    COMBINED,  SHADE,    0,           0,        0,         SHADE
#define G_CC_BLENDIA2           ENVIRONMENT,          SHADE,    COMBINED,  SHADE,    COMBINED,    0,        SHADE,     0
#define G_CC_CHROMA_KEY2        TEXEL0,               CENTER,   SCALE,     0,        0,           0,        0,         0
#define G_CC_HILITERGB2         ENVIRONMENT,          COMBINED, TEXEL0,    COMBINED, 0,           0,        0,         SHADE
#define G_CC_HILITERGBA2        ENVIRONMENT,          COMBINED, TEXEL0,    COMBINED, ENVIRONMENT, COMBINED, TEXEL0,    COMBINED
#define G_CC_HILITERGBDECALA2   ENVIRONMENT,          COMBINED, TEXEL0,    COMBINED, 0,           0,        0,         TEXEL0
#define G_CC_HILITERGBPASSA2    ENVIRONMENT,          COMBINED, TEXEL0,    COMBINED, 0,           0,        0,         COMBINED

/*
 * G_SETOTHERMODE_L sft: shift count
 */
#define G_MDSFT_ALPHACOMPARE 0
#define G_MDSFT_ZSRCSEL      2
#define G_MDSFT_RENDERMODE   3
#define G_MDSFT_BLENDER      16

/*
 * G_SETOTHERMODE_H sft: shift count
 */
#define G_MDSFT_BLENDMASK   0 /* unsupported */
#define G_MDSFT_ALPHADITHER 4
#define G_MDSFT_RGBDITHER   6

#define G_MDSFT_COMBKEY     8
#define G_MDSFT_TEXTCONV    9
#define G_MDSFT_TEXTFILT    12
#define G_MDSFT_TEXTLUT     14
#define G_MDSFT_TEXTLOD     16
#define G_MDSFT_TEXTDETAIL  17
#define G_MDSFT_TEXTPERSP   19
#define G_MDSFT_CYCLETYPE   20
#define G_MDSFT_COLORDITHER 22 /* unsupported in HW 2.0 */
#define G_MDSFT_PIPELINE    23

/* G_SETOTHERMODE_H gPipelineMode */
#define G_PM_1PRIMITIVE (1 << G_MDSFT_PIPELINE)
#define G_PM_NPRIMITIVE (0 << G_MDSFT_PIPELINE)

/* G_SETOTHERMODE_H gSetCycleType */
#define G_CYC_1CYCLE    (0 << G_MDSFT_CYCLETYPE)
#define G_CYC_2CYCLE    (1 << G_MDSFT_CYCLETYPE)
#define G_CYC_COPY      (2 << G_MDSFT_CYCLETYPE)
#define G_CYC_FILL      (3 << G_MDSFT_CYCLETYPE)

/* G_SETOTHERMODE_H gSetTexturePersp */
#define G_TP_NONE       (0 << G_MDSFT_TEXTPERSP)
#define G_TP_PERSP      (1 << G_MDSFT_TEXTPERSP)

/* G_SETOTHERMODE_H gSetTextureDetail */
#define G_TD_CLAMP      (0 << G_MDSFT_TEXTDETAIL)
#define G_TD_SHARPEN    (1 << G_MDSFT_TEXTDETAIL)
#define G_TD_DETAIL     (2 << G_MDSFT_TEXTDETAIL)

/* G_SETOTHERMODE_H gSetTextureLOD */
#define G_TL_TILE       (0 << G_MDSFT_TEXTLOD)
#define G_TL_LOD        (1 << G_MDSFT_TEXTLOD)

/* G_SETOTHERMODE_H gSetTextureLUT */
#define G_TT_NONE       (0 << G_MDSFT_TEXTLUT)
#define G_TT_RGBA16     (2 << G_MDSFT_TEXTLUT)
#define G_TT_IA16       (3 << G_MDSFT_TEXTLUT)

/* G_SETOTHERMODE_H gSetTextureFilter */
#define G_TF_POINT      (0 << G_MDSFT_TEXTFILT)
#define G_TF_AVERAGE    (3 << G_MDSFT_TEXTFILT)
#define G_TF_BILERP     (2 << G_MDSFT_TEXTFILT)

/* G_SETOTHERMODE_H gSetTextureConvert */
#define G_TC_CONV       (0 << G_MDSFT_TEXTCONV)
#define G_TC_FILTCONV   (5 << G_MDSFT_TEXTCONV)
#define G_TC_FILT       (6 << G_MDSFT_TEXTCONV)

/* G_SETOTHERMODE_H gSetCombineKey */
#define G_CK_NONE       (0 << G_MDSFT_COMBKEY)
#define G_CK_KEY        (1 << G_MDSFT_COMBKEY)

/* G_SETOTHERMODE_H gSetColorDither */
#define G_CD_MAGICSQ    (0 << G_MDSFT_RGBDITHER)
#define G_CD_BAYER      (1 << G_MDSFT_RGBDITHER)
#define G_CD_NOISE      (2 << G_MDSFT_RGBDITHER)

#define G_CD_DISABLE    (3 << G_MDSFT_RGBDITHER)
#define G_CD_ENABLE     G_CD_NOISE /* HW 1.0 compatibility mode */

/* G_SETOTHERMODE_H gSetAlphaDither */
#define G_AD_PATTERN    (0 << G_MDSFT_ALPHADITHER)
#define G_AD_NOTPATTERN (1 << G_MDSFT_ALPHADITHER)
#define G_AD_NOISE      (2 << G_MDSFT_ALPHADITHER)
#define G_AD_DISABLE    (3 << G_MDSFT_ALPHADITHER)

/* G_SETOTHERMODE_L gSetAlphaCompare */
#define G_AC_NONE       (0 << G_MDSFT_ALPHACOMPARE)
#define G_AC_THRESHOLD  (1 << G_MDSFT_ALPHACOMPARE)
#define G_AC_DITHER     (3 << G_MDSFT_ALPHACOMPARE)

/* G_SETOTHERMODE_L gSetDepthSource */
#define G_ZS_PIXEL      (0 << G_MDSFT_ZSRCSEL)
#define G_ZS_PRIM       (1 << G_MDSFT_ZSRCSEL)

/* G_SETOTHERMODE_L gSetRenderMode */
#define AA_EN         0x8
#define Z_CMP         0x10
#define Z_UPD         0x20
#define IM_RD         0x40
#define CLR_ON_CVG    0x80
#define CVG_DST_CLAMP 0
#define CVG_DST_WRAP  0x100
#define CVG_DST_FULL  0x200
#define CVG_DST_SAVE  0x300
#define ZMODE_OPA     0
#define ZMODE_INTER   0x400
#define ZMODE_XLU     0x800
#define ZMODE_DEC     0xc00
#define CVG_X_ALPHA   0x1000
#define ALPHA_CVG_SEL 0x2000
#define FORCE_BL      0x4000
#define TEX_EDGE      0x0000 /* used to be 0x8000 */

#define G_BL_CLR_IN  0
#define G_BL_CLR_MEM 1
#define G_BL_CLR_BL  2
#define G_BL_CLR_FOG 3
#define G_BL_1MA     0
#define G_BL_A_MEM   1
#define G_BL_A_IN    0
#define G_BL_A_FOG   1
#define G_BL_A_SHADE 2
#define G_BL_1       2
#define G_BL_0       3

#define GBL_c1(m1a, m1b, m2a, m2b)                        \
    (u32)(m1a) << 30 | (u32)(m1b) << 26 | (u32)(m2a) << 22 | (u32)(m2b) << 18

#define GBL_c2(m1a, m1b, m2a, m2b)                        \
    (u32)(m1a) << 28 | (u32)(m1b) << 24 | (u32)(m2a) << 20 | (u32)(m2b) << 16

#define RM_AA_ZB_OPA_SURF(clk)                                   \
    AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP |              \
    ZMODE_OPA | ALPHA_CVG_SEL |                                  \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

#define RM_RA_ZB_OPA_SURF(clk)                                   \
    AA_EN | Z_CMP | Z_UPD | CVG_DST_CLAMP |                      \
    ZMODE_OPA | ALPHA_CVG_SEL |                                  \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

#define RM_AA_ZB_XLU_SURF(clk)                                 \
    AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG |        \
    FORCE_BL | ZMODE_XLU |                                     \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

#define RM_AA_ZB_OPA_DECAL(clk)                                  \
    AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | ALPHA_CVG_SEL |       \
    ZMODE_DEC |                                                  \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

#define RM_RA_ZB_OPA_DECAL(clk)                                  \
    AA_EN | Z_CMP | CVG_DST_WRAP | ALPHA_CVG_SEL |               \
    ZMODE_DEC |                                                  \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

#define RM_AA_ZB_XLU_DECAL(clk)                                \
    AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG |        \
    FORCE_BL | ZMODE_DEC |                                     \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

#define RM_AA_ZB_OPA_INTER(clk)                                  \
    AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP |              \
    ALPHA_CVG_SEL | ZMODE_INTER |                                \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

#define RM_RA_ZB_OPA_INTER(clk)                                  \
    AA_EN | Z_CMP | Z_UPD | CVG_DST_CLAMP |                      \
    ALPHA_CVG_SEL | ZMODE_INTER |                                \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

#define RM_AA_ZB_XLU_INTER(clk)                                \
    AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG |        \
    FORCE_BL | ZMODE_INTER |                                   \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

#define RM_AA_ZB_XLU_LINE(clk)                                 \
    AA_EN | Z_CMP | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA |      \
    ALPHA_CVG_SEL | FORCE_BL | ZMODE_XLU |                     \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

#define RM_AA_ZB_DEC_LINE(clk)                                 \
    AA_EN | Z_CMP | IM_RD | CVG_DST_SAVE | CVG_X_ALPHA |       \
    ALPHA_CVG_SEL | FORCE_BL | ZMODE_DEC |                     \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

#define RM_AA_ZB_TEX_EDGE(clk)                                   \
    AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP |              \
    CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE |         \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

#define RM_AA_ZB_TEX_INTER(clk)                                  \
    AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP |              \
    CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_INTER | TEX_EDGE |       \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

#define RM_AA_ZB_SUB_SURF(clk)                                   \
    AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL |               \
    ZMODE_OPA | ALPHA_CVG_SEL |                                  \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

#define RM_AA_ZB_PCL_SURF(clk)                                 \
    AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP |            \
    ZMODE_OPA | G_AC_DITHER |                                  \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

#define RM_AA_ZB_OPA_TERR(clk)                                 \
    AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP |            \
    ZMODE_OPA | ALPHA_CVG_SEL |                                \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

#define RM_AA_ZB_TEX_TERR(clk)                                 \
    AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP |            \
    CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE |       \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

#define RM_AA_ZB_SUB_TERR(clk)                                 \
    AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL |             \
    ZMODE_OPA | ALPHA_CVG_SEL |                                \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)


#define RM_AA_OPA_SURF(clk)                                      \
    AA_EN | IM_RD | CVG_DST_CLAMP |                              \
    ZMODE_OPA | ALPHA_CVG_SEL |                                  \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

#define RM_RA_OPA_SURF(clk)                                      \
    AA_EN | CVG_DST_CLAMP |                                      \
    ZMODE_OPA | ALPHA_CVG_SEL |                                  \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

#define RM_AA_XLU_SURF(clk)                                    \
    AA_EN | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | FORCE_BL |     \
    ZMODE_OPA |                                                \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

#define RM_AA_XLU_LINE(clk)                                    \
    AA_EN | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA |              \
    ALPHA_CVG_SEL | FORCE_BL | ZMODE_OPA |                     \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

#define RM_AA_DEC_LINE(clk)                                    \
    AA_EN | IM_RD | CVG_DST_FULL | CVG_X_ALPHA |               \
    ALPHA_CVG_SEL | FORCE_BL | ZMODE_OPA |                     \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

#define RM_AA_TEX_EDGE(clk)                                      \
    AA_EN | IM_RD | CVG_DST_CLAMP |                              \
    CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE |         \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

#define RM_AA_SUB_SURF(clk)                                      \
    AA_EN | IM_RD | CVG_DST_FULL |                               \
    ZMODE_OPA | ALPHA_CVG_SEL |                                  \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

#define RM_AA_PCL_SURF(clk)                                    \
    AA_EN | IM_RD | CVG_DST_CLAMP |                            \
    ZMODE_OPA | G_AC_DITHER |                                  \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

#define RM_AA_OPA_TERR(clk)                                    \
    AA_EN | IM_RD | CVG_DST_CLAMP |                            \
    ZMODE_OPA | ALPHA_CVG_SEL |                                \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

#define RM_AA_TEX_TERR(clk)                                    \
    AA_EN | IM_RD | CVG_DST_CLAMP |                            \
    CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE |       \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

#define RM_AA_SUB_TERR(clk)                                    \
    AA_EN | IM_RD | CVG_DST_FULL |                             \
    ZMODE_OPA | ALPHA_CVG_SEL |                                \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)


#define RM_ZB_OPA_SURF(clk)                                      \
    Z_CMP | Z_UPD | CVG_DST_FULL | ALPHA_CVG_SEL |               \
    ZMODE_OPA |                                                  \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

#define RM_ZB_XLU_SURF(clk)                                    \
    Z_CMP | IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_XLU |      \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

#define RM_ZB_OPA_DECAL(clk)                                     \
    Z_CMP | CVG_DST_FULL | ALPHA_CVG_SEL | ZMODE_DEC |           \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

#define RM_ZB_XLU_DECAL(clk)                                   \
    Z_CMP | IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_DEC |      \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

#define RM_ZB_CLD_SURF(clk)                                    \
    Z_CMP | IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_XLU |      \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

#define RM_ZB_OVL_SURF(clk)                                    \
    Z_CMP | IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_DEC |      \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

#define RM_ZB_PCL_SURF(clk)                              \
    Z_CMP | Z_UPD | CVG_DST_FULL | ZMODE_OPA |           \
    G_AC_DITHER |                                        \
    GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1)


#define RM_OPA_SURF(clk)                                 \
    CVG_DST_CLAMP | FORCE_BL | ZMODE_OPA |               \
    GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1)

#define RM_XLU_SURF(clk)                                       \
    IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_OPA |              \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

#define RM_TEX_EDGE(clk)                                     \
    CVG_DST_CLAMP | CVG_X_ALPHA | ALPHA_CVG_SEL | FORCE_BL | \
    ZMODE_OPA | TEX_EDGE | AA_EN |                           \
    GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1)

#define RM_CLD_SURF(clk)                                       \
    IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_OPA |              \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

#define RM_PCL_SURF(clk)                                 \
    CVG_DST_FULL | FORCE_BL | ZMODE_OPA |                \
    G_AC_DITHER |                                        \
    GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1)

#define RM_ADD(clk)                                           \
    IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_OPA |             \
    GBL_c##clk(G_BL_CLR_IN, G_BL_A_FOG, G_BL_CLR_MEM, G_BL_1)

#define RM_NOOP(clk)       \
    GBL_c##clk(0, 0, 0, 0)

#define RM_VISCVG(clk)                                       \
    IM_RD | FORCE_BL |                                       \
    GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_BL, G_BL_A_MEM)

/* for rendering to an 8-bit framebuffer */
#define RM_OPA_CI(clk)                                   \
    CVG_DST_CLAMP | ZMODE_OPA |                          \
    GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1)



#define G_RM_AA_ZB_OPA_SURF   RM_AA_ZB_OPA_SURF(1)
#define G_RM_AA_ZB_OPA_SURF2  RM_AA_ZB_OPA_SURF(2)
#define G_RM_AA_ZB_XLU_SURF   RM_AA_ZB_XLU_SURF(1)
#define G_RM_AA_ZB_XLU_SURF2  RM_AA_ZB_XLU_SURF(2)
#define G_RM_AA_ZB_OPA_DECAL  RM_AA_ZB_OPA_DECAL(1)
#define G_RM_AA_ZB_OPA_DECAL2 RM_AA_ZB_OPA_DECAL(2)
#define G_RM_AA_ZB_XLU_DECAL  RM_AA_ZB_XLU_DECAL(1)
#define G_RM_AA_ZB_XLU_DECAL2 RM_AA_ZB_XLU_DECAL(2)
#define G_RM_AA_ZB_OPA_INTER  RM_AA_ZB_OPA_INTER(1)
#define G_RM_AA_ZB_OPA_INTER2 RM_AA_ZB_OPA_INTER(2)
#define G_RM_AA_ZB_XLU_INTER  RM_AA_ZB_XLU_INTER(1)
#define G_RM_AA_ZB_XLU_INTER2 RM_AA_ZB_XLU_INTER(2)
#define G_RM_AA_ZB_XLU_LINE   RM_AA_ZB_XLU_LINE(1)
#define G_RM_AA_ZB_XLU_LINE2  RM_AA_ZB_XLU_LINE(2)
#define G_RM_AA_ZB_DEC_LINE   RM_AA_ZB_DEC_LINE(1)
#define G_RM_AA_ZB_DEC_LINE2  RM_AA_ZB_DEC_LINE(2)
#define G_RM_AA_ZB_TEX_EDGE   RM_AA_ZB_TEX_EDGE(1)
#define G_RM_AA_ZB_TEX_EDGE2  RM_AA_ZB_TEX_EDGE(2)
#define G_RM_AA_ZB_TEX_INTER  RM_AA_ZB_TEX_INTER(1)
#define G_RM_AA_ZB_TEX_INTER2 RM_AA_ZB_TEX_INTER(2)
#define G_RM_AA_ZB_SUB_SURF   RM_AA_ZB_SUB_SURF(1)
#define G_RM_AA_ZB_SUB_SURF2  RM_AA_ZB_SUB_SURF(2)
#define G_RM_AA_ZB_PCL_SURF   RM_AA_ZB_PCL_SURF(1)
#define G_RM_AA_ZB_PCL_SURF2  RM_AA_ZB_PCL_SURF(2)
#define G_RM_AA_ZB_OPA_TERR   RM_AA_ZB_OPA_TERR(1)
#define G_RM_AA_ZB_OPA_TERR2  RM_AA_ZB_OPA_TERR(2)
#define G_RM_AA_ZB_TEX_TERR   RM_AA_ZB_TEX_TERR(1)
#define G_RM_AA_ZB_TEX_TERR2  RM_AA_ZB_TEX_TERR(2)
#define G_RM_AA_ZB_SUB_TERR   RM_AA_ZB_SUB_TERR(1)
#define G_RM_AA_ZB_SUB_TERR2  RM_AA_ZB_SUB_TERR(2)

#define G_RM_RA_ZB_OPA_SURF   RM_RA_ZB_OPA_SURF(1)
#define G_RM_RA_ZB_OPA_SURF2  RM_RA_ZB_OPA_SURF(2)
#define G_RM_RA_ZB_OPA_DECAL  RM_RA_ZB_OPA_DECAL(1)
#define G_RM_RA_ZB_OPA_DECAL2 RM_RA_ZB_OPA_DECAL(2)
#define G_RM_RA_ZB_OPA_INTER  RM_RA_ZB_OPA_INTER(1)
#define G_RM_RA_ZB_OPA_INTER2 RM_RA_ZB_OPA_INTER(2)

#define G_RM_AA_OPA_SURF      RM_AA_OPA_SURF(1)
#define G_RM_AA_OPA_SURF2     RM_AA_OPA_SURF(2)
#define G_RM_AA_XLU_SURF      RM_AA_XLU_SURF(1)
#define G_RM_AA_XLU_SURF2     RM_AA_XLU_SURF(2)
#define G_RM_AA_XLU_LINE      RM_AA_XLU_LINE(1)
#define G_RM_AA_XLU_LINE2     RM_AA_XLU_LINE(2)
#define G_RM_AA_DEC_LINE      RM_AA_DEC_LINE(1)
#define G_RM_AA_DEC_LINE2     RM_AA_DEC_LINE(2)
#define G_RM_AA_TEX_EDGE      RM_AA_TEX_EDGE(1)
#define G_RM_AA_TEX_EDGE2     RM_AA_TEX_EDGE(2)
#define G_RM_AA_SUB_SURF      RM_AA_SUB_SURF(1)
#define G_RM_AA_SUB_SURF2     RM_AA_SUB_SURF(2)
#define G_RM_AA_PCL_SURF      RM_AA_PCL_SURF(1)
#define G_RM_AA_PCL_SURF2     RM_AA_PCL_SURF(2)
#define G_RM_AA_OPA_TERR      RM_AA_OPA_TERR(1)
#define G_RM_AA_OPA_TERR2     RM_AA_OPA_TERR(2)
#define G_RM_AA_TEX_TERR      RM_AA_TEX_TERR(1)
#define G_RM_AA_TEX_TERR2     RM_AA_TEX_TERR(2)
#define G_RM_AA_SUB_TERR      RM_AA_SUB_TERR(1)
#define G_RM_AA_SUB_TERR2     RM_AA_SUB_TERR(2)

#define G_RM_RA_OPA_SURF      RM_RA_OPA_SURF(1)
#define G_RM_RA_OPA_SURF2     RM_RA_OPA_SURF(2)

#define G_RM_ZB_OPA_SURF      RM_ZB_OPA_SURF(1)
#define G_RM_ZB_OPA_SURF2     RM_ZB_OPA_SURF(2)
#define G_RM_ZB_XLU_SURF      RM_ZB_XLU_SURF(1)
#define G_RM_ZB_XLU_SURF2     RM_ZB_XLU_SURF(2)
#define G_RM_ZB_OPA_DECAL     RM_ZB_OPA_DECAL(1)
#define G_RM_ZB_OPA_DECAL2    RM_ZB_OPA_DECAL(2)
#define G_RM_ZB_XLU_DECAL     RM_ZB_XLU_DECAL(1)
#define G_RM_ZB_XLU_DECAL2    RM_ZB_XLU_DECAL(2)
#define G_RM_ZB_CLD_SURF      RM_ZB_CLD_SURF(1)
#define G_RM_ZB_CLD_SURF2     RM_ZB_CLD_SURF(2)
#define G_RM_ZB_OVL_SURF      RM_ZB_OVL_SURF(1)
#define G_RM_ZB_OVL_SURF2     RM_ZB_OVL_SURF(2)
#define G_RM_ZB_PCL_SURF      RM_ZB_PCL_SURF(1)
#define G_RM_ZB_PCL_SURF2     RM_ZB_PCL_SURF(2)

#define G_RM_OPA_SURF         RM_OPA_SURF(1)
#define G_RM_OPA_SURF2        RM_OPA_SURF(2)
#define G_RM_XLU_SURF         RM_XLU_SURF(1)
#define G_RM_XLU_SURF2        RM_XLU_SURF(2)
#define G_RM_CLD_SURF         RM_CLD_SURF(1)
#define G_RM_CLD_SURF2        RM_CLD_SURF(2)
#define G_RM_TEX_EDGE         RM_TEX_EDGE(1)
#define G_RM_TEX_EDGE2        RM_TEX_EDGE(2)
#define G_RM_PCL_SURF         RM_PCL_SURF(1)
#define G_RM_PCL_SURF2        RM_PCL_SURF(2)
#define G_RM_ADD              RM_ADD(1)
#define G_RM_ADD2             RM_ADD(2)
#define G_RM_NOOP             RM_NOOP(1)
#define G_RM_NOOP2            RM_NOOP(2)
#define G_RM_VISCVG           RM_VISCVG(1)
#define G_RM_VISCVG2          RM_VISCVG(2)
#define G_RM_OPA_CI           RM_OPA_CI(1)
#define G_RM_OPA_CI2          RM_OPA_CI(2)


#define G_RM_FOG_SHADE_A GBL_c1(G_BL_CLR_FOG, G_BL_A_SHADE, G_BL_CLR_IN, G_BL_1MA)
#define G_RM_FOG_PRIM_A  GBL_c1(G_BL_CLR_FOG, G_BL_A_FOG,   G_BL_CLR_IN, G_BL_1MA)
#define G_RM_PASS        GBL_c1(G_BL_CLR_IN,  G_BL_0,       G_BL_CLR_IN, G_BL_1)

/*
 * G_SETCONVERT: K0-5
 */
#define G_CV_K0 175
#define G_CV_K1 -43
#define G_CV_K2 -89
#define G_CV_K3 222
#define G_CV_K4 114
#define G_CV_K5 42

/*
 * G_SETSCISSOR: interlace mode
 */
#define G_SC_NON_INTERLACE  0
#define G_SC_ODD_INTERLACE  3
#define G_SC_EVEN_INTERLACE 2

/* flags to inhibit pushing of the display list (on branch) */
#define G_DL_PUSH   0x00
#define G_DL_NOPUSH 0x01

/*
 * BEGIN C-specific section: (typedef's)
 */
#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS)

/*
 * Data Structures
 *
 * NOTE:
 * The DMA transfer hardware requires 64-bit aligned, 64-bit multiple-
 * sized transfers. This important hardware optimization is unfortunately
 * reflected in the programming interface, with some structures
 * padded and alignment enforced.
 *
 * Since structures are aligned to the boundary of the "worst-case"
 * element, we can't depend on the C compiler to align things
 * properly.
 *
 * 64-bit structure alignment is enforced by wrapping structures with
 * unions that contain a dummy "long long int".  Why this works is
 * explained in the ANSI C Spec, or on page 186 of the second edition
 * of K&R, "The C Programming Language".
 *
 * The price we pay for this is a little awkwardness referencing the
 * structures through the union. There is no memory penalty, since
 * all the structures are at least 64-bits the dummy alignment field
 * does not increase the size of the union.
 *
 * Static initialization of these union structures works because
 * the ANSI C spec states that static initialization for unions
 * works by using the first union element. We put the dummy alignment
 * field last for this reason.
 *
 * (it's possible a newer 64-bit compiler from MIPS might make this
 * easier with a flag, but we can't wait for it...)
 *
 */

typedef struct {
	union {
		struct {
			/*0x00*/ s16 x;
			/*0x02*/ s16 y;
			/*0x04*/ s16 z;
		};
		s16 v[3];
	};
	/*0x06*/ u8 flags;
	/*0x07*/ u8 colour;
	/*0x08*/ s16 s;
	/*0x0a*/ s16 t;
} Vtx;

typedef union {
    u32 word;
    u8 bytes[4];
    struct {
        u8 r;
        u8 g;
        u8 b;
        u8 a;
    };
} Col;

/*
 * Sprite structure
 */

typedef struct {
	void  *SourceImagePointer;
	void  *TlutPointer;
	short Stride;
	short SubImageWidth;
	short SubImageHeight;
	char  SourceImageType;
	char  SourceImageBitSize;
	short SourceImageOffsetS;
	short SourceImageOffsetT;
	char  dummy[4];
} uSprite_t;

typedef union {
	uSprite_t     s;
	long long int force_structure_allignment[3];
} uSprite;

/*
 * Triangle face
 */
typedef struct {
#ifdef PLATFORM_BIG_ENDIAN
	unsigned char flag;
	unsigned char v[3];
#else
	unsigned char v[3]; // reverse order
	unsigned char flag;
#endif
} Tri;

#ifdef PLATFORM_BIG_ENDIAN
#define GFX_TRI_VTX(i) (i)
#else
#define GFX_TRI_VTX(i) (2 - i)
#endif

/*
 * 4x4 matrix, fixed point s15.16 format.
 * First 8 words are integer portion of the 4x4 matrix
 * Last 8 words are the fraction portion of the 4x4 matrix
 */
#ifdef GBI_FLOATS
// 4x4 float matrix
typedef float Mtx_t[4][4];
#else
typedef int32_t Mtx_t[4][4];
#endif

typedef union {
	Mtx_t         m;
	long long int force_structure_alignment;
} Mtx;

/*
 * Viewport
 */

/*
 *
 * This magic value is the maximum INTEGER z-range of the hardware
 * (there are also 16-bits of fraction, which are introduced during
 * any transformations). This is not just a good idea, it's the law.
 * Feeding the hardware eventual z-coordinates (after any transforms
 * or scaling) bigger than this, will not work.
 *
 * This number is DIFFERENT than G_MAXFBZ, which is the maximum value
 * you want to use to initialize the z-buffer.
 *
 * The reason these are different is mildly interesting, but too long
 * to explain here. It is basically the result of optimizations in the
 * hardware. A more generic API might hide this detail from the users,
 * but we don't have the ucode to do that...
 *
 */
#define G_MAXZ 0x03ff /* 10 bits of integer screen-Z precision */

/*
 * The viewport structure elements have 2 bits of fraction, necessary
 * to accomodate the sub-pixel positioning scaling for the hardware.
 * This can also be exploited to handle odd-sized viewports.
 *
 * Accounting for these fractional bits, using the default projection
 * and viewing matrices, the viewport structure is initialized thusly:
 *
 *   (SCREEN_WD/2)*4, (SCREEN_HT/2)*4, G_MAXZ, 0,
 *   (SCREEN_WD/2)*4, (SCREEN_HT/2)*4, 0, 0,
 */
typedef struct {
	short vscale[4]; /* scale, 2 bits fraction */
	short vtrans[4]; /* translate, 2 bits fraction */
} Vp_t;

typedef union {
	Vp_t          vp;
	long long int force_structure_alignment;
} Vp;

/*
 * MOVEMEM indices
 *
 * Each of these indexes an entry in a dmem table
 * which points to a 1-4 word block of dmem in
 * which to store a 1-4 word DMA.
 *
 */
#define G_MV_VIEWPORT 0x80
#define G_MV_LOOKATY  0x82
#define G_MV_LOOKATX  0x84
#define G_MV_L0       0x86
#define G_MV_L1       0x88
#define G_MV_L2       0x8a
#define G_MV_L3       0x8c
#define G_MV_L4       0x8e
#define G_MV_L5       0x90
#define G_MV_L6       0x92
#define G_MV_L7       0x94
#define G_MV_TXTATT   0x96
#define G_MV_MATRIX_1 0x9e /* NOTE: this is in moveword table */
#define G_MV_MATRIX_2 0x98
#define G_MV_MATRIX_3 0x9a
#define G_MV_MATRIX_4 0x9c

/*
 * MOVEWORD indices
 *
 * Each of these indexes an entry in a dmem table
 * which points to a word in dmem in dmem where
 * an immediate word will be stored.
 *
 */
#define G_MW_MATRIX    0x00 /* NOTE: also used by movemem */
#define G_MW_NUMLIGHT  0x02
#define G_MW_CLIP      0x04
#define G_MW_SEGMENT   0x06
#define G_MW_FOG       0x08
#define G_MW_LIGHTCOL  0x0a
#define G_MW_POINTS    0x0c
#define G_MW_PERSPNORM 0x0e

/*
 * These are offsets from the address in the dmem table
 */
#define G_MWO_NUMLIGHT       0x00
#define G_MWO_CLIP_RNX       0x04
#define G_MWO_CLIP_RNY       0x0c
#define G_MWO_CLIP_RPX       0x14
#define G_MWO_CLIP_RPY       0x1c
#define G_MWO_SEGMENT_0      0x00
#define G_MWO_SEGMENT_1      0x01
#define G_MWO_SEGMENT_2      0x02
#define G_MWO_SEGMENT_3      0x03
#define G_MWO_SEGMENT_4      0x04
#define G_MWO_SEGMENT_5      0x05
#define G_MWO_SEGMENT_6      0x06
#define G_MWO_SEGMENT_7      0x07
#define G_MWO_SEGMENT_8      0x08
#define G_MWO_SEGMENT_9      0x09
#define G_MWO_SEGMENT_A      0x0a
#define G_MWO_SEGMENT_B      0x0b
#define G_MWO_SEGMENT_C      0x0c
#define G_MWO_SEGMENT_D      0x0d
#define G_MWO_SEGMENT_E      0x0e
#define G_MWO_SEGMENT_F      0x0f
#define G_MWO_FOG            0x00
#define G_MWO_aLIGHT_1       0x00
#define G_MWO_bLIGHT_1       0x04
#define G_MWO_aLIGHT_2       0x20
#define G_MWO_bLIGHT_2       0x24
#define G_MWO_aLIGHT_3       0x40
#define G_MWO_bLIGHT_3       0x44
#define G_MWO_aLIGHT_4       0x60
#define G_MWO_bLIGHT_4       0x64
#define G_MWO_aLIGHT_5       0x80
#define G_MWO_bLIGHT_5       0x84
#define G_MWO_aLIGHT_6       0xa0
#define G_MWO_bLIGHT_6       0xa4
#define G_MWO_aLIGHT_7       0xc0
#define G_MWO_bLIGHT_7       0xc4
#define G_MWO_aLIGHT_8       0xe0
#define G_MWO_bLIGHT_8       0xe4
#define G_MWO_MATRIX_XX_XY_I 0x00
#define G_MWO_MATRIX_XZ_XW_I 0x04
#define G_MWO_MATRIX_YX_YY_I 0x08
#define G_MWO_MATRIX_YZ_YW_I 0x0c
#define G_MWO_MATRIX_ZX_ZY_I 0x10
#define G_MWO_MATRIX_ZZ_ZW_I 0x14
#define G_MWO_MATRIX_WX_WY_I 0x18
#define G_MWO_MATRIX_WZ_WW_I 0x1c
#define G_MWO_MATRIX_XX_XY_F 0x20
#define G_MWO_MATRIX_XZ_XW_F 0x24
#define G_MWO_MATRIX_YX_YY_F 0x28
#define G_MWO_MATRIX_YZ_YW_F 0x2c
#define G_MWO_MATRIX_ZX_ZY_F 0x30
#define G_MWO_MATRIX_ZZ_ZW_F 0x34
#define G_MWO_MATRIX_WX_WY_F 0x38
#define G_MWO_MATRIX_WZ_WW_F 0x3c
#define G_MWO_POINT_RGBA     0x10
#define G_MWO_POINT_ST       0x14
#define G_MWO_POINT_XYSCREEN 0x18
#define G_MWO_POINT_ZSCREEN  0x1c

/*
 * Light structure.
 *
 * Note: only directional (infinite) lights are currently supported.
 *
 * Note: the weird order is for the DMEM alignment benefit of
 * the microcode.
 *
 */

typedef struct {
	unsigned char col[3];  /* diffuse light value (rgba) */
	char          pad1;
	unsigned char colc[3]; /* copy of diffuse light value (rgba) */
	char          pad2;
	signed char   dir[3];  /* direction of light (normalized) */
	char          pad3;
} Light_t;

typedef struct {
	unsigned char col[3];  /* ambient light value (rgba) */
	char          pad1;
	unsigned char colc[3]; /* copy of ambient light value (rgba) */
	char          pad2;
} Ambient_t;

typedef struct {
	int x1,y1,x2,y2; /* texture offsets for highlight 1/2 */
} Hilite_t;

typedef union {
	Light_t       l;
	long long int force_structure_alignment[2];
} Light;

typedef union {
	Ambient_t     l;
	long long int force_structure_alignment[1];
} Ambient;

typedef struct {
	Ambient a;
	Light   l[7];
} Lightsn;

typedef struct {
	Ambient a;
	Light   l[1];
} Lights0;

typedef struct {
	Ambient a;
	Light   l[1];
} Lights1;

typedef struct {
	Ambient a;
	Light   l[2];
} Lights2;

typedef struct {
	Light l[2];
} LookAt;

typedef union {
	Hilite_t h;
	long int force_structure_alignment[4];
} Hilite;

#define gdSPDefLights0(ar,ag,ab)                  \
{                                                 \
    {{ {ar,ag,ab},0,{ar,ag,ab},0}},               \
    {{{ { 0, 0, 0},0,{ 0, 0, 0},0,{ 0, 0, 0},0}}} \
}

#define gdSPDefLights1(ar,ag,ab,r1,g1,b1,x1,y1,z1) \
{                                                  \
    {{ {ar,ag,ab},0,{ar,ag,ab},0}},                \
    {{{ {r1,g1,b1},0,{r1,g1,b1},0,{x1,y1,z1},0}}}  \
}

#define gdSPDefLights2(ar,ag,ab,r1,g1,b1,x1,y1,z1,r2,g2,b2,x2,y2,z2) \
{                                                                    \
    {{ {ar,ag,ab},0,{ar,ag,ab},0}},                                  \
    {{{ {r1,g1,b1},0,{r1,g1,b1},0,{x1,y1,z1},0}},                    \
        {{ {r2,g2,b2},0,{r2,g2,b2},0,{x2,y2,z2},0}}}                 \
}

#define gdSPDefLookAt(rightx,righty,rightz,upx,upy,upz) \
{                                                       \
    {{ {{0,0,0},0,{0,0,0},0,{rightx,righty,rightz},0}}, \
    { {{0,0x80,0},0,{0,0x80,0},0,{upx,upy,upz},0}}}     \
}

/*
 *  Graphics DMA Packet
 */
#ifdef PLATFORM_64BIT
typedef struct {
    intptr_t par : 24;
    intptr_t cmd : 8;
    intptr_t len : 32;
    uintptr_t addr;
} Gdma;
#else
typedef struct {
#ifdef PLATFORM_BIG_ENDIAN
	int          cmd:8;
	unsigned int par:8;
	unsigned int len:16;
	unsigned int addr;
#else // NOTE: changing signedness mid int will break up the bitfield on normal platforms, even BE
	int len:16;
	int par:8;
	int cmd:8;
	unsigned int addr;
#endif
} Gdma;
#endif

/*
 * Graphics Immediate Mode Packet types
 */
typedef struct {
#ifdef PLATFORM_BIG_ENDIAN
	int cmd:8;
	int pad:24;
#else
    int pad:24;
    int cmd:8;
#endif
	Tri tri;
} Gtri;

typedef struct {
#ifdef PLATFORM_BIG_ENDIAN
	unsigned char cmd:8;
	unsigned char pad:8;
	unsigned char z4:4;
	unsigned char z3:4;
	unsigned char z2:4;
	unsigned char z1:4;
	unsigned char y4:4;
	unsigned char x4:4;
	unsigned char y3:4;
	unsigned char x3:4;
	unsigned char y2:4;
	unsigned char x2:4;
	unsigned char y1:4;
	unsigned char x1:4;
#else
	unsigned char z1:4;
	unsigned char z2:4;
	unsigned char z3:4;
	unsigned char z4:4;
	unsigned char pad:8;
	unsigned char cmd:8;
#ifdef PLATFORM_64BIT
    unsigned char pad2[4];
#endif
	unsigned char x1:4;
	unsigned char y1:4;
	unsigned char x2:4;
	unsigned char y2:4;
	unsigned char x3:4;
	unsigned char y3:4;
	unsigned char x4:4;
	unsigned char y4:4;
#ifdef PLATFORM_64BIT
    unsigned char pad3[4];
#endif
#endif
} Gtri4;

typedef struct {
	int           cmd:8;
	int           pad1:24;
	int           pad2:24;
	unsigned char param:8;
} Gpopmtx;

typedef struct {
	int cmd:8;
	int pad0:8;
	int mw_index:8;
	int number:8;
	int pad1:8;
	int base:24;
} Gsegment;

typedef struct {
	int          cmd:8;
	int          pad0:8;
	int          sft:8;
	int          len:8;
	unsigned int data:32;
} GsetothermodeL;

typedef struct {
	int          cmd:8;
	int          pad0:8;
	int          sft:8;
	int          len:8;
	unsigned int data:32;
} GsetothermodeH;

typedef struct {
#ifdef PLATFORM_BIG_ENDIAN
	unsigned char  cmd;
	unsigned char  lodscale;
	unsigned char  tile;
	unsigned char  on;
	unsigned short s;
	unsigned short t;
#else
	unsigned char  on;
	unsigned char  tile;
	unsigned char  lodscale;
	unsigned char  cmd;
	unsigned short t;
	unsigned short s;
#endif
} Gtexture;

typedef struct {
	int cmd:8;
	int pad:24;
	Tri line;
} Gline3D;

typedef struct {
	int       cmd:8;
	int       pad1:24;
	short int pad2;
	short int scale;
} Gperspnorm;


/*
 * RDP Packet types
 */
typedef struct {
	int          cmd:8;
	unsigned int fmt:3;
	unsigned int siz:2;
	unsigned int pad:7;
	unsigned int wd:12; /* really only 10 bits, extra */
	unsigned int dram;  /* to account for 1024        */
} Gsetimg;

typedef struct {
	int          cmd:8;
	unsigned int muxs0:24;
	unsigned int muxs1:32;
} Gsetcombine;

typedef struct {
	int           cmd:8;
	unsigned char pad;
	unsigned char prim_min_level;
	unsigned char prim_level;
	unsigned long color;
} Gsetcolor;

typedef struct {
	int          cmd:8;
	int          x0:10;
	int          x0frac:2;
	int          y0:10;
	int          y0frac:2;
	unsigned int pad:8;
	int          x1:10;
	int          x1frac:2;
	int          y1:10;
	int          y1frac:2;
} Gfillrect;

typedef struct {
	int          cmd:8;
	unsigned int fmt:3;
	unsigned int siz:2;
	unsigned int pad0:1;
	unsigned int line:9;
	unsigned int tmem:9;
	unsigned int pad1:5;
	unsigned int tile:3;
	unsigned int palette:4;
	unsigned int ct:1;
	unsigned int mt:1;
	unsigned int maskt:4;
	unsigned int shiftt:4;
	unsigned int cs:1;
	unsigned int ms:1;
	unsigned int masks:4;
	unsigned int shifts:4;
} Gsettile;

typedef struct {
	int          cmd:8;
	unsigned int sl:12;
	unsigned int tl:12;
	int          pad:5;
	unsigned int tile:3;
	unsigned int sh:12;
	unsigned int th:12;
} Gloadtile;

typedef Gloadtile Gloadblock;

typedef Gloadtile Gsettilesize;

typedef Gloadtile Gloadtlut;

typedef struct {
	unsigned int cmd:8;   /* command                     */
	unsigned int xl:12;   /* X coordinate of upper left  */
	unsigned int yl:12;   /* Y coordinate of upper left  */
	unsigned int pad1:5;  /* Padding                     */
	unsigned int tile:3;  /* Tile descriptor index       */
	unsigned int xh:12;   /* X coordinate of lower right */
	unsigned int yh:12;   /* Y coordinate of lower right */
	unsigned int s:16;    /* S texture coord at top left */
	unsigned int t:16;    /* T texture coord at top left */
	unsigned int dsdx:16; /* Change in S per change in X */
	unsigned int dtdy:16; /* Change in T per change in Y */
} Gtexrect;

#define MakeTexRect(xh,yh,flip,tile,xl,yl,s,t,dsdx,dtdy)          \
    G_TEXRECT, xh, yh, 0, flip, 0, tile, xl, yl, s, t, dsdx, dtdy

/*
 * Textured rectangles are 128 bits not 64 bits
 */
typedef struct {
	unsigned long w0;
	unsigned long w1;
	unsigned long w2;
	unsigned long w3;
} TexRect;

/*
 * Generic Gfx Packet
 */
typedef struct {
	uintptr_t w0;
	uintptr_t w1;
} Gwords;

// xxxxxxxx 11223344 44555566 66666777
// 88888888 99999999 9999aaaa aaaaaaaa
typedef struct {
#ifdef PLATFORM_BIG_ENDIAN
	unsigned int cmd:8;
	unsigned int unk08:2;
	unsigned int unk0a:2;
	unsigned int unk0c:2;
	unsigned int unk0e:4;
	unsigned int unk12:4;
	unsigned int flags:7;
	unsigned int subcmd:3;
	unsigned int unk20:8;
	unsigned int tile1:12;
	unsigned int tile2:12;
#else
	unsigned int subcmd:3;
	unsigned int flags:7;
	unsigned int unk12:4;
	unsigned int unk0e:4;
	unsigned int unk0c:2;
	unsigned int unk0a:2;
	unsigned int unk08:2;
	unsigned int cmd:8;
	unsigned int tile2:12;
	unsigned int tile1:12;
	unsigned int unk20:8;
#endif
} GunkC0;

typedef struct {
#ifdef PLATFORM_BIG_ENDIAN
	unsigned int cmd:8;
	unsigned int unk08:4;
	unsigned int unk0c:4;
	unsigned int unk10:16;
	unsigned int seg:8;
	unsigned int offset:24;
#else
	unsigned int unk10:16;
	unsigned int unk0c:4;
	unsigned int unk08:4;
	unsigned int cmd:8;
	unsigned int offset:24;
	unsigned int seg:8;
#endif
} Gvtx;

/*
 * This union is the fundamental type of the display list.
 * It is, by law, exactly 64 bits in size.
 */
typedef union {
	Gwords         words;
#ifdef PLATFORM_64BIT
	u8             bytes[16];
#else
	u8             bytes[8];
#endif
	Gdma           dma;
	Gvtx           vtx;
	Gtri           tri;
	Gtri4          tri4;
	Gline3D        line;
	Gtexture       texture;
#ifdef PLATFORM_N64                           /* the rest is not needed on other platforms and some of em screw up the size */
	Gpopmtx        popmtx;
	Gsegment       segment;
	GsetothermodeH setothermodeH;
	GsetothermodeL setothermodeL;
	Gperspnorm     perspnorm;
	Gsetimg        setimg;
	Gsetcombine    setcombine;
	Gsetcolor      setcolor;
	Gfillrect      fillrect;                  /* use for setscissor also */
	Gsettile       settile;
	Gloadtile      loadtile;                  /* use for loadblock also, th is dxt */
	Gsettilesize   settilesize;
	Gloadtlut      loadtlut;
#endif
	GunkC0         unkc0;
#ifdef PLATFORM_64BIT
	long long int  force_structure_alignment[2];
#else
	long long int  force_structure_alignment;
#endif
} Gfx;

#ifdef PLATFORM_BIG_ENDIAN
#define GFX_W0_BYTE(i) (i)
#define GFX_W1_BYTE(i) (4 + (i))
#elif PLATFORM_64BIT
#define GFX_W0_BYTE(i) (3 - (i))
#define GFX_W1_BYTE(i) (11 - (i))
#else
#define GFX_W0_BYTE(i) (3 - (i))
#define GFX_W1_BYTE(i) (7 - (i))
#endif

/*
 * Macros to assemble the graphics display list
 */

/*
 * DMA macros
 */
#define gDma0p(pkt, c, s, l)                                  \
{                                                             \
    Gfx *_g = (Gfx *)(pkt);                                   \
                                                              \
    _g->words.w0 = _SHIFTL((c), 24, 8) | _SHIFTL((l), 0, 24); \
    _g->words.w1 = (uintptr_t)(s);                            \
}

#define gsDma0p(c, s, l)                                         \
{                                                                \
    _SHIFTL((c), 24, 8) | _SHIFTL((l), 0, 24), (uintptr_t)(s)    \
}

#define gDma1p(pkt, c, s, l, p)                                 \
{                                                               \
    Gfx *_g = (Gfx *)(pkt);                                     \
                                                                \
    _g->words.w0 = (_SHIFTL((c), 24, 8) | _SHIFTL((p), 16, 8) | \
            _SHIFTL((l), 0, 16));                               \
    _g->words.w1 = (uintptr_t)(s);                              \
}

#define gsDma1p(c, s, l, p)                      \
{                                                \
    (_SHIFTL((c), 24, 8) | _SHIFTL((p), 16, 8) | \
     _SHIFTL((l), 0, 16)),                       \
    (uintptr_t)(s)                               \
}

#define gDma2p(pkt, c, adrs, len, idx, ofs)                      \
{                                                                \
    Gfx *_g = (Gfx *)(pkt);                                      \
    _g->words.w0 = (_SHIFTL((c),24,8)|_SHIFTL(((len)-1)/8,19,5)| \
            _SHIFTL((ofs)/8,8,8)|_SHIFTL((idx),0,8));            \
    _g->words.w1 = (uintptr_t)(adrs);                            \
}

#define gsDma2p(c, adrs, len, idx, ofs)           \
{                                                 \
    (_SHIFTL((c),24,8)|_SHIFTL(((len)-1)/8,19,5)| \
     _SHIFTL((ofs)/8,8,8)|_SHIFTL((idx),0,8)),    \
    (uintptr_t)(adrs)                             \
}

#define gSPNoOp(pkt) gDma0p(pkt, G_SPNOOP, 0, 0)
#define gsSPNoOp()   gsDma0p(G_SPNOOP, 0, 0)

#define gSPMatrix(pkt, m, p) gDma1p(pkt, G_MTX, m, sizeof(Mtx), p)
#define gsSPMatrix(m, p)     gsDma1p(G_MTX, m, sizeof(Mtx), p)

#define gSPVertex(pkt, v, n, v0)                           \
    gDma1p(pkt, G_VTX, v, sizeof(Vtx)*(n),((n)-1)<<4|(v0))

#define gsSPVertex(v, n, v0)                            \
    gsDma1p(G_VTX, v, sizeof(Vtx)*(n), ((n)-1)<<4|(v0))

#define gSPViewport(pkt,v)                                   \
    gDma1p((pkt), G_MOVEMEM, (v), sizeof(Vp), G_MV_VIEWPORT)

#define gsSPViewport(v)                                      \
    gsDma1p(      G_MOVEMEM, (v), sizeof(Vp), G_MV_VIEWPORT)

#define gSPDisplayList(pkt,dl)  gDma1p(pkt,G_DL,dl,0,G_DL_PUSH)
#define gsSPDisplayList(   dl)  gsDma1p(   G_DL,dl,0,G_DL_PUSH)

#define gSPBranchList(pkt,dl)   gDma1p(pkt,G_DL,dl,0,G_DL_NOPUSH)
#define gsSPBranchList(   dl)   gsDma1p(   G_DL,dl,0,G_DL_NOPUSH)

#define gSPSprite2DBase(pkt, s) gDma1p(pkt, G_SPRITE2D_BASE, s, sizeof(uSprite), 0)
#define gsSPSprite2DBase(s)     gsDma1p(G_SPRITE2D_BASE, s, sizeof(uSprite), 0)

/*
 * RSP short command (no DMA required) macros
 */
#define gImmp0(pkt, c)                  \
{                                       \
    Gfx *_g = (Gfx *)(pkt);             \
    _g->words.w0 = _SHIFTL((c), 24, 8); \
}

#define gsImmp0(c)      \
{                       \
    _SHIFTL((c), 24, 8) \
}

#define gImmp1(pkt, c, p0)              \
{                                       \
    Gfx *_g = (Gfx *)(pkt);             \
                                        \
    _g->words.w0 = _SHIFTL((c), 24, 8); \
    _g->words.w1 = (uintptr_t)(p0);     \
}

#define gsImmp1(c, p0)                      \
{                                           \
    _SHIFTL((c), 24, 8), (uintptr_t)(p0)    \
}

#define gImmp2(pkt, c, p0, p1)                                  \
{                                                               \
    Gfx *_g = (Gfx *)(pkt);                                     \
                                                                \
    _g->words.w0 = _SHIFTL((c), 24, 8);                         \
    _g->words.w1 = _SHIFTL((p0), 16, 16) | _SHIFTL((p1), 8, 8); \
}

#define gsImmp2(c, p0, p1)                                            \
{                                                                     \
    _SHIFTL((c), 24, 8),  _SHIFTL((p0), 16, 16) | _SHIFTL((p1), 8, 8) \
}

#define gImmp3(pkt, c, p0, p1, p2)                                \
{                                                                 \
    Gfx *_g = (Gfx *)(pkt);                                       \
                                                                  \
    _g->words.w0 = _SHIFTL((c), 24, 8);                           \
    _g->words.w1 = (_SHIFTL((p0), 16, 16) | _SHIFTL((p1), 8, 8) | \
            _SHIFTL((p2), 0, 8));                                 \
}

#define gsImmp3(c, p0, p1, p2)                         \
{                                                      \
    _SHIFTL((c), 24, 8), (_SHIFTL((p0), 16, 16) |      \
            _SHIFTL((p1), 8, 8) | _SHIFTL((p2), 0, 8)) \
}

#define gImmp21(pkt, c, p0, p1, dat)                              \
{                                                                 \
    Gfx *_g = (Gfx *)(pkt);                                       \
                                                                  \
    _g->words.w0 = (_SHIFTL((c), 24, 8)  | _SHIFTL((p0), 8, 16) | \
            _SHIFTL((p1), 0, 8));                                 \
    _g->words.w1 = (uintptr_t) (dat);                             \
}

#define gsImmp21(c, p0, p1, dat)                                      \
{                                                                     \
    _SHIFTL((c), 24, 8) | _SHIFTL((p0), 8, 16) | _SHIFTL((p1), 0, 8), \
    (uintptr_t) (dat)                                                 \
}

#define gMoveWd(pkt, index, offset, data)           \
    gImmp21((pkt), G_MOVEWORD, offset, index, data)

#define gsMoveWd(index, offset, data)         \
    gsImmp21(G_MOVEWORD, offset, index, data)

/* Sprite immediate macros, there is also a sprite dma macro above */

#define gSPSprite2DScaleFlip(pkt, sx, sy, fx, fy)          \
{                                                          \
    Gfx *_g = (Gfx *)(pkt);                                \
                                                           \
    _g->words.w0 = (_SHIFTL(G_SPRITE2D_SCALEFLIP, 24, 8) | \
            _SHIFTL((fx), 8, 8) |                          \
            _SHIFTL((fy), 0, 8));                          \
    _g->words.w1 = (_SHIFTL((sx), 16, 16) |                \
            _SHIFTL((sy),  0, 16));                        \
}

#define gsSPSprite2DScaleFlip(sx, sy, fx, fy) \
{                                             \
    (_SHIFTL(G_SPRITE2D_SCALEFLIP, 24, 8) |   \
     _SHIFTL((fx), 8, 8) |                    \
     _SHIFTL((fy), 0, 8)),                    \
    (_SHIFTL((sx), 16, 16) |                  \
     _SHIFTL((sy),  0, 16))                   \
}

#define gSPSprite2DDraw(pkt, px, py)                  \
{                                                     \
    Gfx *_g = (Gfx *)(pkt);                           \
                                                      \
    _g->words.w0 = (_SHIFTL(G_SPRITE2D_DRAW, 24, 8)); \
    _g->words.w1 = (_SHIFTL((px), 16, 16) |           \
            _SHIFTL((py),  0, 16));                   \
}

#define gsSPSprite2DDraw(px, py)       \
{                                      \
    (_SHIFTL(G_SPRITE2D_DRAW, 24, 8)), \
    (_SHIFTL((px), 16, 16) |           \
     _SHIFTL((py),  0, 16))            \
}


/*
 * Note: the SP1Triangle() and line macros multiply the vertex indices
 * by 10, this is an optimization for the microcode.
 */
#define __gsSP1Triangle_w1f(v0, v1, v2, flag)     \
    (_SHIFTL((flag), 24,8)|_SHIFTL((v0)*10,16,8)| \
     _SHIFTL((v1)*10, 8,8)|_SHIFTL((v2)*10, 0,8))

#define __gsSPLine3D_w1f(v0, v1, wd, flag)        \
    (_SHIFTL((flag), 24,8)|_SHIFTL((v0)*10,16,8)| \
     _SHIFTL((v1)*10, 8,8)|_SHIFTL((wd),    0,8))

/***
 ***  1 Triangle
 ***/
#define gSP1Triangle(pkt, v0, v1, v2, flag)               \
{                                                         \
    Gfx *_g = (Gfx *)(pkt);                               \
                                                          \
    _g->words.w0 = _SHIFTL(G_TRI1, 24, 8);                \
    _g->words.w1 = __gsSP1Triangle_w1f(v0, v1, v2, flag); \
}

#define gsSP1Triangle(v0, v1, v2, flag)   \
{                                         \
    _SHIFTL(G_TRI1, 24, 8),               \
    __gsSP1Triangle_w1f(v0, v1, v2, flag) \
}

/***
 ***  Line
 ***/
#define gSPLine3D(pkt, v0, v1, flag)                  \
{                                                     \
    Gfx *_g = (Gfx *)(pkt);                           \
                                                      \
    _g->words.w0 = _SHIFTL(G_LINE3D, 24, 8);          \
    _g->words.w1 = __gsSPLine3D_w1f(v0, v1, 0, flag); \
}

#define gsSPLine3D(v0, v1, flag)      \
{                                     \
    _SHIFTL(G_LINE3D, 24, 8),         \
    __gsSPLine3D_w1f(v0, v1, 0, flag) \
}

/***
 ***  LineW
 ***/
/* these macros are the same as SPLine3D, except they have an
 * additional parameter for width. The width is added to the "minimum"
 * thickness, which is 1.5 pixels. The units for width are in
 * half-pixel units, so a width of 1 translates to (.5 + 1.5) or
 * a 2.0 pixels wide line.
 */
#define gSPLineW3D(pkt, v0, v1, wd, flag)              \
{                                                      \
    Gfx *_g = (Gfx *)(pkt);                            \
                                                       \
    _g->words.w0 = _SHIFTL(G_LINE3D, 24, 8);           \
    _g->words.w1 = __gsSPLine3D_w1f(v0, v1, wd, flag); \
}

#define gsSPLineW3D(v0, v1, wd, flag)  \
{                                      \
    _SHIFTL(G_LINE3D, 24, 8),          \
    __gsSPLine3D_w1f(v0, v1, wd, flag) \
}

/***
 ***  1 Quadrangle
 ***/
#define gSP1Quadrangle(pkt, v0, v1, v2, v3, flag)                \
{                                                                \
    Gfx *_g = (Gfx *)(pkt);                                      \
                                                                 \
    _g->words.w0 = (_SHIFTL(G_TRI2, 24, 8)|                      \
            __gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag));        \
    _g->words.w1 =  __gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag); \
}

#define gsSP1Quadrangle(v0, v1, v2, v3, flag)      \
{                                                  \
    (_SHIFTL(G_TRI2, 24, 8)|                       \
     __gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag)), \
    __gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag)    \
}

// Removed in PD
#define gSPCullDisplayList(pkt,vstart,vend)                \
{                                                          \
    Gfx *_g = (Gfx *)(pkt);                                \
                                                           \
    _g->words.w0 = _SHIFTL(G_CULLDL, 24, 8) |              \
    ((0x0f & (vstart))*40);                                \
    _g->words.w1 = (uintptr_t)((0x0f & ((vend)+1))*40);    \
}

// Removed in PD
#define gsSPCullDisplayList(vstart,vend)               \
{                                                      \
    _SHIFTL(G_CULLDL, 24, 8) | ((0x0f & (vstart))*40), \
    ((0x0f & ((vend)+1))*40)                           \
}

#define gSPSegment(pkt, segment, base)            \
    gMoveWd(pkt, G_MW_SEGMENT, (segment)*4, base)

#define gsSPSegment(segment, base)            \
    gsMoveWd(G_MW_SEGMENT, (segment)*4, base)

#ifdef PLATFORM_N64
#define SEGADDR(x) x
#define UNSEGADDR(x) x
#else
// we mark all segmented addresses so that it'll be easier to recognize them later
#define SEGADDR(x) ((void *)((uintptr_t)(x) | 1))
#define UNSEGADDR(x) ((uintptr_t)(x) & ~1)
#endif

/*
 * Clipping Macros
 */
#define FR_NEG_FRUSTRATIO_1 0x00000001
#define FR_POS_FRUSTRATIO_1 0x0000ffff
#define FR_NEG_FRUSTRATIO_2 0x00000002
#define FR_POS_FRUSTRATIO_2 0x0000fffe
#define FR_NEG_FRUSTRATIO_3 0x00000003
#define FR_POS_FRUSTRATIO_3 0x0000fffd
#define FR_NEG_FRUSTRATIO_4 0x00000004
#define FR_POS_FRUSTRATIO_4 0x0000fffc
#define FR_NEG_FRUSTRATIO_5 0x00000005
#define FR_POS_FRUSTRATIO_5 0x0000fffb
#define FR_NEG_FRUSTRATIO_6 0x00000006
#define FR_POS_FRUSTRATIO_6 0x0000fffa
/*
 * r should be one of: FRUSTRATIO_1, FRUSTRATIO_2, FRUSTRATIO_3, ... FRUSTRATIO_6
 */
#define gSPClipRatio(pkt, r)                             \
{                                                        \
    gMoveWd(pkt, G_MW_CLIP, G_MWO_CLIP_RNX, FR_NEG_##r); \
    gMoveWd(pkt, G_MW_CLIP, G_MWO_CLIP_RNY, FR_NEG_##r); \
    gMoveWd(pkt, G_MW_CLIP, G_MWO_CLIP_RPX, FR_POS_##r); \
    gMoveWd(pkt, G_MW_CLIP, G_MWO_CLIP_RPY, FR_POS_##r); \
}

#define gsSPClipRatio(r)                             \
    gsMoveWd(G_MW_CLIP, G_MWO_CLIP_RNX, FR_NEG_##r), \
    gsMoveWd(G_MW_CLIP, G_MWO_CLIP_RNY, FR_NEG_##r), \
    gsMoveWd(G_MW_CLIP, G_MWO_CLIP_RPX, FR_POS_##r), \
    gsMoveWd(G_MW_CLIP, G_MWO_CLIP_RPY, FR_POS_##r)

/*
 * Insert values into Matrix
 *
 * where = element of matrix (byte offset)
 * num   = new element (32 bit value replacing 2 int or 2 frac matrix
 *                                 componants
 */
#define gSPInsertMatrix(pkt, where, num)  \
    gMoveWd(pkt, G_MW_MATRIX, where, num)

#define gsSPInsertMatrix(where, num)  \
    gsMoveWd(G_MW_MATRIX, where, num)

/*
 * Load new matrix directly
 *
 * mptr = pointer to matrix
 */
#define gSPForceMatrix(pkt, mptr)                                 \
{                                                                 \
    gDma1p(pkt, G_MOVEMEM, mptr,              16, G_MV_MATRIX_1); \
    gDma1p(pkt, G_MOVEMEM, (char *)(mptr)+16, 16, G_MV_MATRIX_2); \
    gDma1p(pkt, G_MOVEMEM, (char *)(mptr)+32, 16, G_MV_MATRIX_3); \
    gDma1p(pkt, G_MOVEMEM, (char *)(mptr)+48, 16, G_MV_MATRIX_4); \
}

#define gsSPForceMatrix(mptr)                                 \
    gsDma1p(G_MOVEMEM, mptr,              16, G_MV_MATRIX_1), \
    gsDma1p(G_MOVEMEM, (char *)(mptr)+16, 16, G_MV_MATRIX_2), \
    gsDma1p(G_MOVEMEM, (char *)(mptr)+32, 16, G_MV_MATRIX_3), \
    gsDma1p(G_MOVEMEM, (char *)(mptr)+48, 16, G_MV_MATRIX_4)

/*
 * Insert values into Points
 *
 * point = point number 0-15
 * where = which element of point to modify (byte offset into point)
 * num   = new value (32 bit)
 */
#define gSPModifyVertex(pkt, vtx, where, val)        \
    gMoveWd(pkt, G_MW_POINTS, (vtx)*40+(where), val)

#define gsSPModifyVertex(vtx, where, val)        \
    gsMoveWd(G_MW_POINTS, (vtx)*40+(where), val)

/*
 * Lighting Macros
 */
#define NUML(n)     (((n)+1)*32 + 0x80000000)

#define NUMLIGHTS_0 1
#define NUMLIGHTS_1 1
#define NUMLIGHTS_2 2
#define NUMLIGHTS_3 3
#define NUMLIGHTS_4 4
#define NUMLIGHTS_5 5
#define NUMLIGHTS_6 6
#define NUMLIGHTS_7 7
/*
 * n should be one of: NUMLIGHTS_0, NUMLIGHTS_1, ..., NUMLIGHTS_7
 * NOTE: in addition to the number of directional lights specified,
 *       there is always 1 ambient light
 */
#define gSPNumLights(pkt, n)                             \
    gMoveWd(pkt, G_MW_NUMLIGHT, G_MWO_NUMLIGHT, NUML(n))

#define gsSPNumLights(n)                             \
    gsMoveWd(G_MW_NUMLIGHT, G_MWO_NUMLIGHT, NUML(n))

#define LIGHT_1 1
#define LIGHT_2 2
#define LIGHT_3 3
#define LIGHT_4 4
#define LIGHT_5 5
#define LIGHT_6 6
#define LIGHT_7 7
#define LIGHT_8 8

/*
 * l should point to a Light struct
 * n should be one of: LIGHT_1, LIGHT_2, ..., LIGHT_8
 * NOTE: the highest numbered light is always the ambient light (eg if there are
 *       3 directional lights defined: gsSPNumLights(NUMLIGHTS_3), then lights
 *       LIGHT_1 through LIGHT_3 will be the directional lights and light
 *       LIGHT_4 will be the ambient light.
 */
#define gSPLight(pkt, l, n)                                    \
    gDma1p(pkt, G_MOVEMEM, l, sizeof(Light),((n)-1)*2+G_MV_L0)

#define gsSPLight(l, n)                                    \
    gsDma1p(G_MOVEMEM, l, sizeof(Light),((n)-1)*2+G_MV_L0)

/*
 * gSPLightColor changes color of light without recalculating light direction
 * col is a 32 bit word with r,g,b,a (alpha is ignored)
 * n should be one of LIGHT_1, LIGHT_2, ..., LIGHT_8
 */
#define gSPLightColor(pkt, n, col)                \
{                                                 \
    gMoveWd(pkt, G_MW_LIGHTCOL, G_MWO_a##n, col); \
    gMoveWd(pkt, G_MW_LIGHTCOL, G_MWO_b##n, col); \
}

#define gsSPLightColor(n, col)                \
    gsMoveWd(G_MW_LIGHTCOL, G_MWO_a##n, col), \
    gsMoveWd(G_MW_LIGHTCOL, G_MWO_b##n, col)

/* These macros use a structure "name" which is init'd with the gdSPDefLights macros*/

#define gSPSetLights0(pkt,name)    \
{                                  \
    gSPNumLights(pkt,NUMLIGHTS_0); \
    gSPLight(pkt,&name.l[0],1);    \
    gSPLight(pkt,&name.a,2);       \
}

#define gsSPSetLights0(name)    \
    gsSPNumLights(NUMLIGHTS_0), \
    gsSPLight(&name.l[0],1),    \
    gsSPLight(&name.a,2)

#define gSPSetLights1(pkt,name)    \
{                                  \
    gSPNumLights(pkt,NUMLIGHTS_1); \
    gSPLight(pkt,&name.l[0],1);    \
    gSPLight(pkt,&name.a,2);       \
}

#define gsSPSetLights1(name)    \
    gsSPNumLights(NUMLIGHTS_1), \
    gsSPLight(&name.l[0],1),    \
    gsSPLight(&name.a,2)

/*
 * Reflection/Hiliting Macros
 */
#define gSPLookAtX(pkt, l) gDma1p(pkt, G_MOVEMEM, l, sizeof(Light),G_MV_LOOKATX)
#define gsSPLookAtX(l)     gsDma1p(    G_MOVEMEM, l, sizeof(Light),G_MV_LOOKATX)
#define gSPLookAtY(pkt, l) gDma1p(pkt, G_MOVEMEM, l, sizeof(Light),G_MV_LOOKATY)
#define gsSPLookAtY(l)     gsDma1p(    G_MOVEMEM, l, sizeof(Light),G_MV_LOOKATY)

#define gSPLookAt(pkt, la)          \
{                                   \
    gSPLookAtX(pkt,la)              \
    gSPLookAtY(pkt,(char *)(la)+16) \
}

#define gsSPLookAt(la)           \
    gsSPLookAtX(la),             \
    gsSPLookAtY((char *)(la)+16)

#define gDPSetHilite1Tile(pkt, tile, hilite, width, height)                                      \
    gDPSetTileSize(pkt, tile, (hilite)->h.x1 & 0xfff, (hilite)->h.y1 & 0xfff,                    \
            ((((width)-1)*4)+(hilite)->h.x1) & 0xfff, ((((height)-1)*4)+(hilite)->h.y1) & 0xfff)

#define gsDPSetHilite1Tile(tile, hilite, width, height)                                          \
    gsDPSetTileSize(tile, (hilite)->h.x1 & 0xfff, (hilite)->h.y1 & 0xfff,                        \
            ((((width)-1)*4)+(hilite)->h.x1) & 0xfff, ((((height)-1)*4)+(hilite)->h.y1) & 0xfff)

#define gDPSetHilite2Tile(pkt, tile, hilite, width, height)                                      \
    gDPSetTileSize(pkt, tile, (hilite)->h.x2 & 0xfff, (hilite)->h.y2 & 0xfff,                    \
            ((((width)-1)*4)+(hilite)->h.x2) & 0xfff, ((((height)-1)*4)+(hilite)->h.y2) & 0xfff)

#define gsDPSetHilite2Tile(tile, hilite, width, height)                                          \
    gsDPSetTileSize(tile, (hilite)->h.x2 & 0xfff, (hilite)->h.y2 & 0xfff,                        \
            ((((width)-1)*4)+(hilite)->h.x2) & 0xfff, ((((height)-1)*4)+(hilite)->h.y2) & 0xfff)

/*
 * FOG macros
 * fm = z multiplier
 * fo = z offset
 * FOG FORMULA:    alpha(fog) = (eyespace z) * fm  + fo  CLAMPED 0 to 255
 *   note: (eyespace z) ranges -1 to 1
 *
 * Alternate method of setting fog:
 * min, max: range 0 to 1000: 0=nearplane, 1000=farplane
 * min is where fog begins (usually less than max and often 0)
 * max is where fog is thickest (usually 1000)
 *
 */
#define gSPFogFactor(pkt, fm, fo)                   \
    gMoveWd(pkt, G_MW_FOG, G_MWO_FOG,               \
            (_SHIFTL(fm,16,16) | _SHIFTL(fo,0,16)))

#define gsSPFogFactor(fm, fo)                       \
    gsMoveWd(G_MW_FOG, G_MWO_FOG,                   \
            (_SHIFTL(fm,16,16) | _SHIFTL(fo,0,16)))

#define gSPFogPosition(pkt, min, max)                        \
    gMoveWd(pkt, G_MW_FOG, G_MWO_FOG,                        \
            (_SHIFTL((128000/((max)-(min))),16,16) |         \
             _SHIFTL(((500-(min))*256/((max)-(min))),0,16)))

#define gsSPFogPosition(min, max)                            \
    gsMoveWd(G_MW_FOG, G_MWO_FOG,                            \
            (_SHIFTL((128000/((max)-(min))),16,16) |         \
             _SHIFTL(((500-(min))*256/((max)-(min))),0,16)))

/*
 * Macros to turn texture on/off
 */
#define gSPTexture(pkt, s, t, level, tile, on)             \
{                                                          \
    Gfx *_g = (Gfx *)(pkt);                                \
                                                           \
    _g->words.w0 = (_SHIFTL(G_TEXTURE,24,8)|               \
            _SHIFTL((level),11,3)|_SHIFTL((tile),8,3)|     \
            _SHIFTL((on),0,8));                            \
    _g->words.w1 = (_SHIFTL((s),16,16)|_SHIFTL((t),0,16)); \
}

#define gsSPTexture(s, t, level, tile, on)                         \
{                                                                  \
    (_SHIFTL(G_TEXTURE,24,8)|                                      \
     _SHIFTL((level),11,3)|_SHIFTL((tile),8,3)|_SHIFTL((on),0,8)), \
    (_SHIFTL((s),16,16)|_SHIFTL((t),0,16))                         \
}

/*
 * Different version of SPTexture macro, has an additional parameter
 * which is currently reserved in the microcode.
 */
#define gSPTextureL(pkt, s, t, level, xparam, tile, on)             \
{                                                                   \
    Gfx *_g = (Gfx *)(pkt);                                         \
                                                                    \
    _g->words.w0 = (_SHIFTL(G_TEXTURE,24,8)|_SHIFTL((xparam),16,8)| \
            _SHIFTL((level),11,3)|_SHIFTL((tile),8,3)|              \
            _SHIFTL((on),0,8));                                     \
    _g->words.w1 = (_SHIFTL((s),16,16)|_SHIFTL((t),0,16));          \
}

#define gsSPTextureL(s, t, level, xparam, tile, on)                \
{                                                                  \
    (_SHIFTL(G_TEXTURE,24,8)|_SHIFTL((xparam),16,8)|               \
     _SHIFTL((level),11,3)|_SHIFTL((tile),8,3)|_SHIFTL((on),0,8)), \
    (_SHIFTL((s),16,16)|_SHIFTL((t),0,16))                         \
}

#define gSPPerspNormalize(pkt, s) gMoveWd(pkt, G_MW_PERSPNORM, 0, (s))
#define gsSPPerspNormalize(s)     gsMoveWd(    G_MW_PERSPNORM, 0, (s))

// Removed in PD
#define gSPPopMatrix(pkt, n) gImmp1(pkt, G_POPMTX, n)
#define gsSPPopMatrix(n)     gsImmp1(    G_POPMTX, n)

#define gSPEndDisplayList(pkt)              \
{                                           \
    Gfx *_g = (Gfx *)(pkt);                 \
                                            \
    _g->words.w0 = _SHIFTL(G_ENDDL, 24, 8); \
    _g->words.w1 = 0;                       \
}

#define gsSPEndDisplayList()   \
{                              \
    _SHIFTL(G_ENDDL, 24, 8), 0 \
}

#define gSPSetGeometryMode(pkt, word)                 \
{                                                     \
    Gfx *_g = (Gfx *)(pkt);                           \
                                                      \
    _g->words.w0 = _SHIFTL(G_SETGEOMETRYMODE, 24, 8); \
    _g->words.w1 = (uintptr_t)(word);                 \
}

#define gsSPSetGeometryMode(word)                           \
{                                                           \
    _SHIFTL(G_SETGEOMETRYMODE, 24, 8), (uintptr_t)(word)    \
}

#define gSPClearGeometryMode(pkt, word)                 \
{                                                       \
    Gfx *_g = (Gfx *)(pkt);                             \
                                                        \
    _g->words.w0 = _SHIFTL(G_CLEARGEOMETRYMODE, 24, 8); \
    _g->words.w1 = (uintptr_t)(word);                   \
}

#define gsSPClearGeometryMode(word)                           \
{                                                             \
    _SHIFTL(G_CLEARGEOMETRYMODE, 24, 8), (uintptr_t)(word)    \
}

#define gSPSetOtherMode(pkt, cmd, sft, len, data)              \
{                                                              \
    Gfx *_g = (Gfx *)(pkt);                                    \
                                                               \
    _g->words.w0 = (_SHIFTL(cmd, 24, 8) | _SHIFTL(sft, 8, 8) | \
            _SHIFTL(len, 0, 8));                               \
    _g->words.w1 = (uintptr_t)(data);                          \
}

#define gsSPSetOtherMode(cmd, sft, len, data)                      \
{                                                                  \
    _SHIFTL(cmd, 24, 8) | _SHIFTL(sft, 8, 8) | _SHIFTL(len, 0, 8), \
    (uintptr_t)(data)                                              \
}

/*
 * RDP setothermode register commands - register shadowed in RSP
 */
#define gDPPipelineMode(pkt, mode)      gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_PIPELINE, 1, mode)
#define gsDPPipelineMode(mode)          gsSPSetOtherMode(    G_SETOTHERMODE_H, G_MDSFT_PIPELINE, 1, mode)
#define gDPSetCycleType(pkt, type)      gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_CYCLETYPE, 2, type)
#define gsDPSetCycleType(type)          gsSPSetOtherMode(    G_SETOTHERMODE_H, G_MDSFT_CYCLETYPE, 2, type)
#define gDPSetTexturePersp(pkt, type)   gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTPERSP, 1, type)
#define gsDPSetTexturePersp(type)       gsSPSetOtherMode(    G_SETOTHERMODE_H, G_MDSFT_TEXTPERSP, 1, type)
#define gDPSetTextureDetail(pkt, type)  gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTDETAIL, 2, type)
#define gsDPSetTextureDetail(type)      gsSPSetOtherMode(    G_SETOTHERMODE_H, G_MDSFT_TEXTDETAIL, 2, type)
#define gDPSetTextureLOD(pkt, type)     gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTLOD, 1, type)
#define gsDPSetTextureLOD(type)         gsSPSetOtherMode(    G_SETOTHERMODE_H, G_MDSFT_TEXTLOD, 1, type)
#define gDPSetTextureLUT(pkt, type)     gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTLUT, 2, type)
#define gsDPSetTextureLUT(type)         gsSPSetOtherMode(    G_SETOTHERMODE_H, G_MDSFT_TEXTLUT, 2, type)
#define gDPSetTextureFilter(pkt, type)  gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTFILT, 2, type)
#define gsDPSetTextureFilter(type)      gsSPSetOtherMode(    G_SETOTHERMODE_H, G_MDSFT_TEXTFILT, 2, type)
#define gDPSetTextureConvert(pkt, type) gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTCONV, 3, type)
#define gsDPSetTextureConvert(type)     gsSPSetOtherMode(    G_SETOTHERMODE_H, G_MDSFT_TEXTCONV, 3, type)
#define gDPSetCombineKey(pkt, type)     gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_COMBKEY, 1, type)
#define gsDPSetCombineKey(type)         gsSPSetOtherMode(    G_SETOTHERMODE_H, G_MDSFT_COMBKEY, 1, type)
#define gDPSetColorDither(pkt, mode)    gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_RGBDITHER, 2, mode)
#define gsDPSetColorDither(mode)        gsSPSetOtherMode(    G_SETOTHERMODE_H, G_MDSFT_RGBDITHER, 2, mode)
#define gDPSetAlphaDither(pkt, mode)    gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_ALPHADITHER, 2, mode)
#define gsDPSetAlphaDither(mode)        gsSPSetOtherMode(    G_SETOTHERMODE_H, G_MDSFT_ALPHADITHER, 2, mode)

/* 'blendmask' is not supported anymore.
 * The bits are reserved for future use.
 * Fri May 26 13:45:55 PDT 1995
 */
#define gDPSetBlendMask(pkt, mask) gDPNoOp(pkt)
#define gsDPSetBlendMask(mask)     gsDPNoOp()

#define gDPSetAlphaCompare(pkt, type) gSPSetOtherMode(pkt, G_SETOTHERMODE_L, G_MDSFT_ALPHACOMPARE, 2, type)
#define gsDPSetAlphaCompare(type)     gsSPSetOtherMode(    G_SETOTHERMODE_L, G_MDSFT_ALPHACOMPARE, 2, type)

#define gDPSetDepthSource(pkt, src)   gSPSetOtherMode(pkt, G_SETOTHERMODE_L, G_MDSFT_ZSRCSEL, 1, src)
#define gsDPSetDepthSource(src)       gsSPSetOtherMode(    G_SETOTHERMODE_L, G_MDSFT_ZSRCSEL, 1, src)

#define gDPSetRenderMode(pkt, c0, c1) gSPSetOtherMode(pkt, G_SETOTHERMODE_L, G_MDSFT_RENDERMODE, 29, (c0) | (c1))
#define gsDPSetRenderMode(c0, c1)     gsSPSetOtherMode(    G_SETOTHERMODE_L, G_MDSFT_RENDERMODE, 29, (c0) | (c1))

#define gSetImage(pkt, cmd, fmt, siz, width, i)                \
{                                                              \
    Gfx *_g = (Gfx *)(pkt);                                    \
                                                               \
    _g->words.w0 = _SHIFTL(cmd, 24, 8) | _SHIFTL(fmt, 21, 3) | \
    _SHIFTL(siz, 19, 2) | _SHIFTL((width)-1, 0, 12);           \
    _g->words.w1 = (uintptr_t)(i);                             \
}

#define gsSetImage(cmd, fmt, siz, width, i)          \
{                                                    \
    _SHIFTL(cmd, 24, 8) | _SHIFTL(fmt, 21, 3) |      \
    _SHIFTL(siz, 19, 2) | _SHIFTL((width)-1, 0, 12), \
    (uintptr_t)(i)                                   \
}

#define gDPSetColorImage(pkt, f, s, w, i) gSetImage(pkt, G_SETCIMG, f, s, w, i)
#define gsDPSetColorImage(f, s, w, i)     gsSetImage(G_SETCIMG, f, s, w, i)

/* use these for new code */
#define gDPSetDepthImage(pkt, i) gSetImage(pkt, G_SETZIMG, 0, 0, 1, i)
#define gsDPSetDepthImage(i)     gsSetImage(G_SETZIMG, 0, 0, 1, i)

/* kept for compatibility */
#define gDPSetMaskImage(pkt, i) gDPSetDepthImage(pkt, i)
#define gsDPSetMaskImage(i)     gsDPSetDepthImage(i)

#define gDPSetTextureImage(pkt, f, s, w, i) gSetImage(pkt, G_SETTIMG, f, s, w, i)
#define gsDPSetTextureImage(f, s, w, i)     gsSetImage(G_SETTIMG, f, s, w, i)

/*
 * RDP macros
 */

#define gDPSetCombine(pkt, muxs0, muxs1)                                 \
{                                                                        \
    Gfx *_g = (Gfx *)(pkt);                                              \
                                                                         \
    _g->words.w0 = _SHIFTL(G_SETCOMBINE, 24, 8) | _SHIFTL(muxs0, 0, 24); \
    _g->words.w1 = (uintptr_t)(muxs1);                                   \
}

#define gsDPSetCombine(muxs0, muxs1)                      \
{                                                         \
    _SHIFTL(G_SETCOMBINE, 24, 8) | _SHIFTL(muxs0, 0, 24), \
    (uintptr_t)(muxs1)                                    \
}

#define GCCc0w0(saRGB0, mRGB0, saA0, mA0)                 \
    (_SHIFTL((saRGB0), 20, 4) | _SHIFTL((mRGB0), 15, 5) | \
     _SHIFTL((saA0), 12, 3) | _SHIFTL((mA0), 9, 3))

#define GCCc1w0(saRGB1, mRGB1)                         \
    (_SHIFTL((saRGB1), 5, 4) | _SHIFTL((mRGB1), 0, 5))

#define GCCc0w1(sbRGB0, aRGB0, sbA0, aA0)                 \
    (_SHIFTL((sbRGB0), 28, 4) | _SHIFTL((aRGB0), 15, 3) | \
     _SHIFTL((sbA0), 12, 3) | _SHIFTL((aA0), 9, 3))

#define GCCc1w1(sbRGB1, saA1, mA1, aRGB1, sbA1, aA1)     \
    (_SHIFTL((sbRGB1), 24, 4) | _SHIFTL((saA1), 21, 3) | \
     _SHIFTL((mA1), 18, 3) | _SHIFTL((aRGB1), 6, 3) |    \
     _SHIFTL((sbA1), 3, 3) | _SHIFTL((aA1), 0, 3))

#define gDPSetCombineLERP(pkt, a0, b0, c0, d0, Aa0, Ab0, Ac0, Ad0, \
        a1, b1, c1, d1, Aa1, Ab1, Ac1, Ad1)                        \
{                                                                  \
    Gfx *_g = (Gfx *)(pkt);                                        \
                                                                   \
    _g->words.w0 = _SHIFTL(G_SETCOMBINE, 24, 8) |                  \
    _SHIFTL(GCCc0w0(G_CCMUX_##a0, G_CCMUX_##c0,                    \
                G_ACMUX_##Aa0, G_ACMUX_##Ac0) |                    \
                GCCc1w0(G_CCMUX_##a1, G_CCMUX_##c1),               \
                0, 24);                                            \
    _g->words.w1 = (unsigned int)(GCCc0w1(G_CCMUX_##b0,            \
                G_CCMUX_##d0,                                      \
                G_ACMUX_##Ab0,                                     \
                G_ACMUX_##Ad0) |                                   \
                GCCc1w1(G_CCMUX_##b1,                              \
                    G_ACMUX_##Aa1,                                 \
                    G_ACMUX_##Ac1,                                 \
                    G_CCMUX_##d1,                                  \
                    G_ACMUX_##Ab1,                                 \
                    G_ACMUX_##Ad1));                               \
}

#define gsDPSetCombineLERP(a0, b0, c0, d0, Aa0, Ab0, Ac0, Ad0, \
        a1, b1, c1, d1, Aa1, Ab1, Ac1, Ad1)                    \
{                                                              \
    _SHIFTL(G_SETCOMBINE, 24, 8) |                             \
    _SHIFTL(GCCc0w0(G_CCMUX_##a0, G_CCMUX_##c0,                \
                G_ACMUX_##Aa0, G_ACMUX_##Ac0) |                \
                GCCc1w0(G_CCMUX_##a1, G_CCMUX_##c1), 0, 24),   \
    (unsigned int)(GCCc0w1(G_CCMUX_##b0, G_CCMUX_##d0,         \
                G_ACMUX_##Ab0, G_ACMUX_##Ad0) |                \
                GCCc1w1(G_CCMUX_##b1, G_ACMUX_##Aa1,           \
                    G_ACMUX_##Ac1, G_CCMUX_##d1,               \
                    G_ACMUX_##Ab1, G_ACMUX_##Ad1))             \
}

/*
 * SetCombineMode macros are NOT redunant. It allow the C preprocessor
 * to substitute single parameter which includes commas in the token and
 * rescan for higher parameter count macro substitution.
 *
 * eg. gsDPSetCombineMode(G_CC_MODULATE, G_CC_MODULATE) turns into
 *     gsDPSetCombineLERP(TEXEL0, 0, SHADE, 0, TEXEL0, 0, SHADE, 0,
 *     TEXEL0, 0, SHADE, 0, TEXEL0, 0, SHADE, 0)
 */

#define gDPSetCombineMode(pkt, a, b) gDPSetCombineLERP(pkt, a, b)
#define gsDPSetCombineMode(a, b)     gsDPSetCombineLERP(a, b)

#define gDPSetColor(pkt, c, d)        \
{                                     \
    Gfx *_g = (Gfx *)(pkt);           \
                                      \
    _g->words.w0 = _SHIFTL(c, 24, 8); \
    _g->words.w1 = (uintptr_t)(d);    \
}

#define gsDPSetColor(c, d)               \
{                                        \
    _SHIFTL(c, 24, 8), (uintptr_t)(d)    \
}

#define DPRGBColor(pkt, cmd, r, g, b, a)             \
    gDPSetColor(pkt, cmd,                            \
            (_SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | \
             _SHIFTL(b, 8, 8) | _SHIFTL(a, 0, 8)))

#define sDPRGBColor(cmd, r, g, b, a)                 \
    gsDPSetColor(cmd,                                \
            (_SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | \
             _SHIFTL(b, 8, 8) | _SHIFTL(a, 0, 8)))

#define gDPSetEnvColor(pkt, r, g, b, a)   DPRGBColor(pkt, G_SETENVCOLOR, r,g,b,a)
#define gsDPSetEnvColor(r, g, b, a)       sDPRGBColor(    G_SETENVCOLOR, r,g,b,a)
#define gDPSetBlendColor(pkt, r, g, b, a) DPRGBColor(pkt, G_SETBLENDCOLOR, r,g,b,a)
#define gsDPSetBlendColor(r, g, b, a)     sDPRGBColor(    G_SETBLENDCOLOR, r,g,b,a)
#define gDPSetFogColor(pkt, r, g, b, a)   DPRGBColor(pkt, G_SETFOGCOLOR, r,g,b,a)
#define gsDPSetFogColor(r, g, b, a)       sDPRGBColor(    G_SETFOGCOLOR, r,g,b,a)
#define gDPSetFillColor(pkt, d)           gDPSetColor(pkt, G_SETFILLCOLOR, (d))
#define gsDPSetFillColor(d)               gsDPSetColor(    G_SETFILLCOLOR, (d))

#define gDPSetPrimDepth(pkt, z, dz)                  \
    gDPSetColor(pkt, G_SETPRIMDEPTH,                 \
            _SHIFTL(z, 16, 16) | _SHIFTL(dz, 0, 16))

#define gsDPSetPrimDepth(z, dz)                       \
    gsDPSetColor(G_SETPRIMDEPTH, _SHIFTL(z, 16, 16) | \
            _SHIFTL(dz, 0, 16))

#define gDPSetPrimColor(pkt, m, l, r, g, b, a)              \
{                                                           \
    Gfx *_g = (Gfx *)(pkt);                                 \
                                                            \
    _g->words.w0 = (_SHIFTL(G_SETPRIMCOLOR, 24, 8) |        \
            _SHIFTL(m, 8, 8) | _SHIFTL(l, 0, 8));           \
    _g->words.w1 = (_SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | \
            _SHIFTL(b, 8, 8) | _SHIFTL(a, 0, 8));           \
}

#define gsDPSetPrimColor(m, l, r, g, b, a)                      \
{                                                               \
    (_SHIFTL(G_SETPRIMCOLOR, 24, 8) | _SHIFTL(m, 8, 8) |        \
     _SHIFTL(l, 0, 8)),                                         \
    (_SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | _SHIFTL(b, 8, 8) | \
     _SHIFTL(a, 0, 8))                                          \
}

/*
 * gDPSetOtherMode (This is for expert user.)
 *
 * This command makes all othermode parameters set.
 * Do not use this command in the same DL with another g*SPSetOtherMode DLs.
 *
 * [Usage]
 *  gDPSetOtherMode(pkt, modeA, modeB)
 *
 *      'modeA' is described all parameters of GroupA GBI command.
 *      'modeB' is also described all parameters of GroupB GBI command.
 *
 *  GroupA:
 *    gDPPipelineMode, gDPSetCycleType, gSPSetTexturePersp,
 *    gDPSetTextureDetail, gDPSetTextureLOD, gDPSetTextureLUT,
 *    gDPSetTextureFilter, gDPSetTextureConvert, gDPSetCombineKey,
 *    gDPSetColorDither, gDPSetAlphaDither
 *
 *  GroupB:
 *    gDPSetAlphaCompare, gDPSetDepthSource, gDPSetRenderMode
 *
 *  Use 'OR' operation to get modeA and modeB.
 *
 *  modeA = G_PM_* | G_CYC_* | G_TP_* | G_TD_* | G_TL_* | G_TT_* | G_TF_*
 *    G_TC_* | G_CK_*  | G_CD_* | G_AD_*;
 *
 *  modeB = G_AC_* | G_ZS_*  | G_RM_* | G_RM_*2;
 */
#define gDPSetOtherMode(pkt, mode0, mode1)                              \
{                                                                       \
    Gfx *_g = (Gfx *)(pkt);                                             \
                                                                        \
    _g->words.w0 = _SHIFTL(G_RDPSETOTHERMODE,24,8)|_SHIFTL(mode0,0,24); \
    _g->words.w1 = (uintptr_t)(mode1);                                  \
}

#define gsDPSetOtherMode(mode0, mode1)                   \
{                                                        \
    _SHIFTL(G_RDPSETOTHERMODE,24,8)|_SHIFTL(mode0,0,24), \
    (uintptr_t)(mode1)                                   \
}

/*
 * Texturing macros
 */

/* These are also defined defined above for Sprite Microcode */

#define G_TX_LOADTILE   7
#define G_TX_RENDERTILE 0
#define G_TX_NOMIRROR   0
#define G_TX_WRAP       0
#define G_TX_MIRROR     0x1
#define G_TX_CLAMP      0x2
#define G_TX_NOMASK     0
#define G_TX_NOLOD      0


#ifndef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif

#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
/*
 *  Dxt is the inverse of the number of 64-bit words in a line of
 *  the texture being loaded using the load_block command.  If
 *  there are any 1's to the right of the 11th fractional bit,
 *  dxt should be rounded up.  The following macros accomplish
 *  this.  The 4b macros are a special case since 4-bit textures
 *  are loaded as 8-bit textures.  Dxt is fixed point 1.11. RJM
 */
#define G_TX_DXT_FRAC 11

/*
 *  For RCP 2.0, the maximum number of texels that can be loaded
 *  using a load_block command is 2048.  In order to load the total
 *  4kB of Tmem, change the texel size when loading to be G_IM_SIZ_16b,
 *  then change the tile to the proper texel size after the load.
 *  The g*DPLoadTextureBlock macros already do this, so this change
 *  will be transparent if you use these macros.  If you use
 *  the g*DPLoadBlock macros directly, you will need to handle this
 *  tile manipulation yourself.  RJM.
 */
#define G_TX_LDBLK_MAX_TXL 2047

#define TXL2WORDS(txls, b_txl) MAX(1, ((txls)*(b_txl)/8))

#define CALC_DXT(width, b_txl)                              \
    (((1 << G_TX_DXT_FRAC) + TXL2WORDS(width, b_txl) - 1) / \
     TXL2WORDS(width, b_txl))

#define TXL2WORDS_4b(txls) MAX(1, ((txls)/16))

#define CALC_DXT_4b(width)                              \
    (((1 << G_TX_DXT_FRAC) + TXL2WORDS_4b(width) - 1) / \
     TXL2WORDS_4b(width))

#define gDPLoadTileGeneric(pkt, c, tile, uls, ult, lrs, lrt)     \
{                                                                \
    Gfx *_g = (Gfx *)(pkt);                                      \
                                                                 \
    _g->words.w0 = _SHIFTL(c, 24, 8) | _SHIFTL(uls, 12, 12) |    \
    _SHIFTL(ult, 0, 12);                                         \
    _g->words.w1 = _SHIFTL(tile, 24, 3) | _SHIFTL(lrs, 12, 12) | \
    _SHIFTL(lrt, 0, 12);                                         \
}

#define gsDPLoadTileGeneric(c, tile, uls, ult, lrs, lrt)              \
{                                                                     \
    _SHIFTL(c, 24, 8) | _SHIFTL(uls, 12, 12) | _SHIFTL(ult, 0, 12),   \
    _SHIFTL(tile, 24, 3) | _SHIFTL(lrs, 12, 12) | _SHIFTL(lrt, 0, 12) \
}

#define gDPSetTileSize(pkt, t, uls, ult, lrs, lrt)                \
    gDPLoadTileGeneric(pkt, G_SETTILESIZE, t, uls, ult, lrs, lrt)

#define gsDPSetTileSize(t, uls, ult, lrs, lrt)                \
    gsDPLoadTileGeneric(G_SETTILESIZE, t, uls, ult, lrs, lrt)

#define gDPLoadTile(pkt, t, uls, ult, lrs, lrt)                \
    gDPLoadTileGeneric(pkt, G_LOADTILE, t, uls, ult, lrs, lrt)

#define gsDPLoadTile(t, uls, ult, lrs, lrt)                \
    gsDPLoadTileGeneric(G_LOADTILE, t, uls, ult, lrs, lrt)

#define gDPSetTile(pkt, fmt, siz, line, tmem, tile, palette, cmt,    \
        maskt, shiftt, cms, masks, shifts)                           \
{                                                                    \
    Gfx *_g = (Gfx *)(pkt);                                          \
                                                                     \
    _g->words.w0 = _SHIFTL(G_SETTILE, 24, 8) | _SHIFTL(fmt, 21, 3) | \
    _SHIFTL(siz, 19, 2) | _SHIFTL(line, 9, 9) |                      \
    _SHIFTL(tmem, 0, 9);                                             \
    _g->words.w1 = _SHIFTL(tile, 24, 3) | _SHIFTL(palette, 20, 4) |  \
    _SHIFTL(cmt, 18, 2) | _SHIFTL(maskt, 14, 4) |                    \
    _SHIFTL(shiftt, 10, 4) |_SHIFTL(cms, 8, 2) |                     \
    _SHIFTL(masks, 4, 4) | _SHIFTL(shifts, 0, 4);                    \
}

#define gsDPSetTile(fmt, siz, line, tmem, tile, palette, cmt,          \
        maskt, shiftt, cms, masks, shifts)                             \
{                                                                      \
    (_SHIFTL(G_SETTILE, 24, 8) | _SHIFTL(fmt, 21, 3) |                 \
     _SHIFTL(siz, 19, 2) | _SHIFTL(line, 9, 9) | _SHIFTL(tmem, 0, 9)), \
    (_SHIFTL(tile, 24, 3) | _SHIFTL(palette, 20, 4) |                  \
     _SHIFTL(cmt, 18, 2) | _SHIFTL(maskt, 14, 4) |                     \
     _SHIFTL(shiftt, 10, 4) | _SHIFTL(cms, 8, 2) |                     \
     _SHIFTL(masks, 4, 4) | _SHIFTL(shifts, 0, 4))                     \
}

/*
 *  For RCP 2.0, the maximum number of texels that can be loaded
 *  using a load_block command is 2048.  In order to load the total
 *  4kB of Tmem, change the texel size when loading to be G_IM_SIZ_16b,
 *  then change the tile to the proper texel size after the load.
 *  The g*DPLoadTextureBlock macros already do this, so this change
 *  will be transparent if you use these macros.  If you use
 *  the g*DPLoadBlock macros directly, you will need to handle this
 *  tile manipulation yourself.  RJM.
 */
#define gDPLoadBlock(pkt, tile, uls, ult, lrs, dxt)          \
{                                                            \
    Gfx *_g = (Gfx *)(pkt);                                  \
                                                             \
    _g->words.w0 = (_SHIFTL(G_LOADBLOCK, 24, 8) |            \
            _SHIFTL(uls, 12, 12) | _SHIFTL(ult, 0, 12));     \
    _g->words.w1 = (_SHIFTL(tile, 24, 3) |                   \
            _SHIFTL((MIN(lrs,G_TX_LDBLK_MAX_TXL)), 12, 12) | \
            _SHIFTL(dxt, 0, 12));                            \
}

#define gsDPLoadBlock(tile, uls, ult, lrs, dxt)           \
{                                                         \
    (_SHIFTL(G_LOADBLOCK, 24, 8) | _SHIFTL(uls, 12, 12) | \
     _SHIFTL(ult, 0, 12)),                                \
    (_SHIFTL(tile, 24, 3) |                               \
     _SHIFTL((MIN(lrs,G_TX_LDBLK_MAX_TXL)), 12, 12) |     \
     _SHIFTL(dxt, 0, 12))                                 \
}

#define gDPLoadTLUTCmd(pkt, tile, count)                              \
{                                                                     \
    Gfx *_g = (Gfx *)pkt;                                             \
                                                                      \
    _g->words.w0 = _SHIFTL(G_LOADTLUT, 24, 8);                        \
    _g->words.w1 = _SHIFTL((tile), 24, 3) | _SHIFTL((count), 14, 10); \
}

#define gsDPLoadTLUTCmd(tile, count)                  \
{                                                     \
    _SHIFTL(G_LOADTLUT, 24, 8),                       \
    _SHIFTL((tile), 24, 3) | _SHIFTL((count), 14, 10) \
}

#define gDPLoadTextureBlock(pkt, timg, fmt, siz, width, height,   \
        pal, cms, cmt, masks, maskt, shifts, shiftt)              \
{                                                                 \
    gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg);      \
    gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE,   \
            0 , cmt, maskt, shiftt, cms, masks, shifts);          \
    gDPLoadSync(pkt);                                             \
    gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0,                        \
            (((width)*(height) + siz##_INCR) >> siz##_SHIFT) -1,  \
            CALC_DXT(width, siz##_BYTES));                        \
    gDPPipeSync(pkt);                                             \
    gDPSetTile(pkt, fmt, siz,                                     \
            (((width) * siz##_LINE_BYTES)+7)>>3, 0,               \
            G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \
            shifts);                                              \
    gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0,                    \
            ((width)-1) << G_TEXTURE_IMAGE_FRAC,                  \
            ((height)-1) << G_TEXTURE_IMAGE_FRAC)                 \
}

#define gDPLoadTextureBlockYuv(pkt, timg, fmt, siz, width, height, \
        pal, cms, cmt, masks, maskt, shifts, shiftt)               \
{                                                                  \
    gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg);       \
    gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE,    \
            0 , cmt, maskt, shiftt, cms, masks, shifts);           \
    gDPLoadSync(pkt);                                              \
    gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0,                         \
            (((width)*(height) + siz##_INCR) >> siz##_SHIFT) -1,   \
            CALC_DXT(width, siz##_BYTES));                         \
    gDPPipeSync(pkt);                                              \
    gDPSetTile(pkt, fmt, siz,                                      \
            (((width) * 1)+7)>>3, 0,                               \
            G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,  \
            shifts);                                               \
    gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0,                     \
            ((width)-1) << G_TEXTURE_IMAGE_FRAC,                   \
            ((height)-1) << G_TEXTURE_IMAGE_FRAC)                  \
}

/* Load fix rww 27jun95 */
/* The S at the end means odd lines are already word Swapped */

#define gDPLoadTextureBlockS(pkt, timg, fmt, siz, width, height,   \
        pal, cms, cmt, masks, maskt, shifts, shiftt)               \
{                                                                  \
    gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg);       \
    gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE,    \
            0 , cmt, maskt, shiftt, cms, masks, shifts);           \
    gDPLoadSync(pkt);                                              \
    gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0,                         \
            (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,0); \
    gDPPipeSync(pkt);                                              \
    gDPSetTile(pkt, fmt, siz,                                      \
            (((width) * siz##_LINE_BYTES)+7)>>3, 0,                \
            G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,  \
            shifts);                                               \
    gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0,                     \
            ((width)-1) << G_TEXTURE_IMAGE_FRAC,                   \
            ((height)-1) << G_TEXTURE_IMAGE_FRAC)                  \
}

/*
 *  Allow tmem address and render tile to be specified.
 *  The S at the end means odd lines are already word Swapped
 */
#define gDPLoadMultiBlockS(pkt, timg, tmem, rtile, fmt, siz, width, \
        height, pal, cms, cmt, masks, maskt, shifts, shiftt)        \
{                                                                   \
    gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg);        \
    gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE,  \
            0 , cmt, maskt, shiftt, cms, masks, shifts);            \
    gDPLoadSync(pkt);                                               \
    gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0,                          \
            (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,0);  \
    gDPPipeSync(pkt);                                               \
    gDPSetTile(pkt, fmt, siz,                                       \
            (((width) * siz##_LINE_BYTES)+7)>>3, tmem,              \
            rtile, pal, cmt, maskt, shiftt, cms, masks,             \
            shifts);                                                \
    gDPSetTileSize(pkt, rtile, 0, 0,                                \
            ((width)-1) << G_TEXTURE_IMAGE_FRAC,                    \
            ((height)-1) << G_TEXTURE_IMAGE_FRAC)                   \
}

#define gDPLoadTextureBlockYuvS(pkt, timg, fmt, siz, width, height, \
        pal, cms, cmt, masks, maskt, shifts, shiftt)                \
{                                                                   \
    gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg);        \
    gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE,     \
            0 , cmt, maskt, shiftt, cms, masks, shifts);            \
    gDPLoadSync(pkt);                                               \
    gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0,                          \
            (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,0);  \
    gDPPipeSync(pkt);                                               \
    gDPSetTile(pkt, fmt, siz,                                       \
            (((width) * 1)+7)>>3, 0,                                \
            G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,   \
            shifts);                                                \
    gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0,                      \
            ((width)-1) << G_TEXTURE_IMAGE_FRAC,                    \
            ((height)-1) << G_TEXTURE_IMAGE_FRAC)                   \
}

/*
 *  allows tmem address to be specified
 */
#define _gDPLoadTextureBlock(pkt, timg, tmem, fmt, siz, width, height, \
        pal, cms, cmt, masks, maskt, shifts, shiftt)                   \
{                                                                      \
    gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg);           \
    gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE,     \
            0, cmt, maskt, shiftt, cms, masks, shifts);                \
    gDPLoadSync(pkt);                                                  \
    gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0,                             \
            (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,        \
            CALC_DXT(width, siz##_BYTES));                             \
    gDPPipeSync(pkt);                                                  \
    gDPSetTile(pkt, fmt, siz, (((width) * siz##_LINE_BYTES)+7)>>3,     \
            tmem, G_TX_RENDERTILE, pal, cmt,                           \
            maskt, shiftt, cms, masks, shifts);                        \
    gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0,                         \
            ((width)-1) << G_TEXTURE_IMAGE_FRAC,                       \
            ((height)-1) << G_TEXTURE_IMAGE_FRAC)                      \
}

/*
 *  allows tmem address and render tile to be specified
 */
#define _gDPLoadTextureBlockTile(pkt, timg, tmem, rtile, fmt, siz, width, \
        height, pal, cms, cmt, masks, maskt, shifts, shiftt)              \
{                                                                         \
    gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg);              \
    gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, 0,     \
            cmt, maskt, shiftt, cms, masks, shifts);                      \
    gDPLoadSync(pkt);                                                     \
    gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0,                                \
            (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,           \
            CALC_DXT(width, siz##_BYTES));                                \
    gDPPipeSync(pkt);                                                     \
    gDPSetTile(pkt, fmt, siz, (((width) * siz##_LINE_BYTES)+7)>>3,        \
            tmem, rtile, pal, cmt,                                        \
            maskt, shiftt, cms, masks, shifts);                           \
    gDPSetTileSize(pkt, rtile, 0, 0,                                      \
            ((width)-1) << G_TEXTURE_IMAGE_FRAC,                          \
            ((height)-1) << G_TEXTURE_IMAGE_FRAC)                         \
}

/*
 *  allows tmem address and render tile to be specified
 */
#define gDPLoadMultiBlock(pkt, timg, tmem, rtile, fmt, siz, width,    \
        height, pal, cms, cmt, masks, maskt, shifts, shiftt)          \
{                                                                     \
    gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg);          \
    gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, 0, \
            cmt, maskt, shiftt, cms, masks, shifts);                  \
    gDPLoadSync(pkt);                                                 \
    gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0,                            \
            (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,       \
            CALC_DXT(width, siz##_BYTES));                            \
    gDPPipeSync(pkt);                                                 \
    gDPSetTile(pkt, fmt, siz, (((width) * siz##_LINE_BYTES)+7)>>3,    \
            tmem, rtile, pal, cmt,                                    \
            maskt, shiftt, cms, masks, shifts);                       \
    gDPSetTileSize(pkt, rtile, 0, 0,                                  \
            ((width)-1) << G_TEXTURE_IMAGE_FRAC,                      \
            ((height)-1) << G_TEXTURE_IMAGE_FRAC)                     \
}

#define gsDPLoadTextureBlock(timg, fmt, siz, width, height,                             \
        pal, cms, cmt, masks, maskt, shifts, shiftt)                                    \
                                                                                        \
        gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg),                            \
        gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, 0,                                        \
                G_TX_LOADTILE, 	0 , cmt, maskt, shiftt, cms,                            \
                masks, shifts),                                                         \
                gsDPLoadSync(),                                                         \
                gsDPLoadBlock(G_TX_LOADTILE, 0, 0,                                      \
                        (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,             \
                        CALC_DXT(width, siz##_BYTES)),                                  \
                        gsDPPipeSync(),                                                 \
                        gsDPSetTile(fmt, siz, ((((width) * siz##_LINE_BYTES)+7)>>3), 0, \
                                G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,   \
                                shifts),                                                \
                                gsDPSetTileSize(G_TX_RENDERTILE, 0, 0,                  \
                                        ((width)-1) << G_TEXTURE_IMAGE_FRAC,            \
                                        ((height)-1) << G_TEXTURE_IMAGE_FRAC)

/* Here is the static form of the pre-swapped texture block loading */
/* See gDPLoadTextureBlockS() for reference.  Basically, just don't
   calculate DxT, use 0 */

#define gsDPLoadTextureBlockS(timg, fmt, siz, width, height,                            \
        pal, cms, cmt, masks, maskt, shifts, shiftt)                                    \
                                                                                        \
        gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg),                            \
        gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE, 0 ,                     \
                cmt, maskt,shiftt, cms, masks, shifts),                                 \
                gsDPLoadSync(),                                                         \
                gsDPLoadBlock(G_TX_LOADTILE, 0, 0,                                      \
                        (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1, 0 ),        \
                        gsDPPipeSync(),                                                 \
                        gsDPSetTile(fmt, siz, ((((width) * siz##_LINE_BYTES)+7)>>3), 0, \
                                G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,   \
                                shifts),                                                \
                                gsDPSetTileSize(G_TX_RENDERTILE, 0, 0,                  \
                                        ((width)-1) << G_TEXTURE_IMAGE_FRAC,            \
                                        ((height)-1) << G_TEXTURE_IMAGE_FRAC)

/*
 *  Allow tmem address to be specified
 */
#define _gsDPLoadTextureBlock(timg, tmem, fmt, siz, width, height,                    \
        pal, cms, cmt, masks, maskt, shifts, shiftt)                                  \
                                                                                      \
        gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg),                          \
        gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE,                    \
                0 , cmt, maskt, shiftt, cms, masks, shifts),                          \
                gsDPLoadSync(),                                                       \
                gsDPLoadBlock(G_TX_LOADTILE, 0, 0,                                    \
                        (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,           \
                        CALC_DXT(width, siz##_BYTES)),                                \
                        gsDPPipeSync(),                                               \
                        gsDPSetTile(fmt, siz,                                         \
                                ((((width) * siz##_LINE_BYTES)+7)>>3), tmem,          \
                                G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \
                                shifts),                                              \
                                gsDPSetTileSize(G_TX_RENDERTILE, 0, 0,                \
                                        ((width)-1) << G_TEXTURE_IMAGE_FRAC,          \
                                        ((height)-1) << G_TEXTURE_IMAGE_FRAC)

/*
 *  Allow tmem address and render_tile to be specified
 */
#define _gsDPLoadTextureBlockTile(timg, tmem, rtile, fmt, siz, width,         \
        height, pal, cms, cmt, masks, maskt, shifts, shiftt)                  \
                                                                              \
        gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg),                  \
        gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE,            \
                0 , cmt, maskt, shiftt, cms, masks, shifts),                  \
                gsDPLoadSync(),                                               \
                gsDPLoadBlock(G_TX_LOADTILE, 0, 0,                            \
                        (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,   \
                        CALC_DXT(width, siz##_BYTES)),                        \
                        gsDPPipeSync(),                                       \
                        gsDPSetTile(fmt, siz,                                 \
                                ((((width) * siz##_LINE_BYTES)+7)>>3), tmem,  \
                                rtile, pal, cmt, maskt, shiftt, cms, masks,   \
                                shifts),                                      \
                                gsDPSetTileSize(rtile, 0, 0,                  \
                                        ((width)-1) << G_TEXTURE_IMAGE_FRAC,  \
                                        ((height)-1) << G_TEXTURE_IMAGE_FRAC)


/*
 *  Allow tmem address and render_tile to be specified, useful when loading
 *  mutilple tiles at a time.
 */
#define gsDPLoadMultiBlock(timg, tmem, rtile, fmt, siz, width,                \
        height, pal, cms, cmt, masks, maskt, shifts, shiftt)                  \
                                                                              \
        gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg),                  \
        gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE,            \
                0 , cmt, maskt, shiftt, cms, masks, shifts),                  \
                gsDPLoadSync(),                                               \
                gsDPLoadBlock(G_TX_LOADTILE, 0, 0,                            \
                        (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,   \
                        CALC_DXT(width, siz##_BYTES)),                        \
                        gsDPPipeSync(),                                       \
                        gsDPSetTile(fmt, siz,                                 \
                                ((((width) * siz##_LINE_BYTES)+7)>>3), tmem,  \
                                rtile, pal, cmt, maskt, shiftt, cms, masks,   \
                                shifts),                                      \
                                gsDPSetTileSize(rtile, 0, 0,                  \
                                        ((width)-1) << G_TEXTURE_IMAGE_FRAC,  \
                                        ((height)-1) << G_TEXTURE_IMAGE_FRAC)

/*
 *  Allows tmem and render tile to be specified.  Useful when loading
 *  several tiles at a time.
 *
 *  Here is the static form of the pre-swapped texture block loading
 *  See gDPLoadTextureBlockS() for reference.  Basically, just don't
 *  calculate DxT, use 0
 */

#define gsDPLoadMultiBlockS(timg, tmem, rtile, fmt, siz, width, height,                    \
        pal, cms, cmt, masks, maskt, shifts, shiftt)                                       \
                                                                                           \
        gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg),                               \
        gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, 0 ,                     \
                cmt, maskt,shiftt, cms, masks, shifts),                                    \
                gsDPLoadSync(),                                                            \
                gsDPLoadBlock(G_TX_LOADTILE, 0, 0,                                         \
                        (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1, 0 ),           \
                        gsDPPipeSync(),                                                    \
                        gsDPSetTile(fmt, siz, ((((width) * siz##_LINE_BYTES)+7)>>3), tmem, \
                                rtile, pal, cmt, maskt, shiftt, cms, masks,                \
                                shifts),                                                   \
                                gsDPSetTileSize(rtile, 0, 0,                               \
                                        ((width)-1) << G_TEXTURE_IMAGE_FRAC,               \
                                        ((height)-1) << G_TEXTURE_IMAGE_FRAC)


#define gDPLoadTextureBlock_4b(pkt, timg, fmt, width, height,     \
        pal, cms, cmt, masks, maskt, shifts, shiftt)              \
{                                                                 \
    gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg);          \
    gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0,    \
            cmt, maskt, shiftt, cms, masks, shifts);              \
    gDPLoadSync(pkt);                                             \
    gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0,                        \
            (((width)*(height)+3)>>2)-1,                          \
            CALC_DXT_4b(width));                                  \
    gDPPipeSync(pkt);                                             \
    gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), 0,   \
            G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \
            shifts);                                              \
    gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0,                    \
            ((width)-1) << G_TEXTURE_IMAGE_FRAC,                  \
            ((height)-1) << G_TEXTURE_IMAGE_FRAC)                 \
}

/* Load fix rww 27jun95 */
/* The S at the end means odd lines are already word Swapped */

#define gDPLoadTextureBlock_4bS(pkt, timg, fmt, width, height,    \
        pal, cms, cmt, masks, maskt, shifts, shiftt)              \
{                                                                 \
    gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg);          \
    gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0,    \
            cmt, maskt, shiftt, cms, masks, shifts);              \
    gDPLoadSync(pkt);                                             \
    gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0,                        \
            (((width)*(height)+3)>>2)-1, 0 );                     \
    gDPPipeSync(pkt);                                             \
    gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), 0,   \
            G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \
            shifts);                                              \
    gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0,                    \
            ((width)-1) << G_TEXTURE_IMAGE_FRAC,                  \
            ((height)-1) << G_TEXTURE_IMAGE_FRAC)                 \
}

/*
 *  4-bit load block.  Useful when loading multiple tiles
 */
#define gDPLoadMultiBlock_4b(pkt, timg, tmem, rtile, fmt, width, height, \
        pal, cms, cmt, masks, maskt, shifts, shiftt)                     \
{                                                                        \
    gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg);                 \
    gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0,        \
            cmt, maskt, shiftt, cms, masks, shifts);                     \
    gDPLoadSync(pkt);                                                    \
    gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0,                               \
            (((width)*(height)+3)>>2)-1,                                 \
            CALC_DXT_4b(width));                                         \
    gDPPipeSync(pkt);                                                    \
    gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), tmem,       \
            rtile, pal, cmt, maskt, shiftt, cms, masks,                  \
            shifts);                                                     \
    gDPSetTileSize(pkt, rtile, 0, 0,                                     \
            ((width)-1) << G_TEXTURE_IMAGE_FRAC,                         \
            ((height)-1) << G_TEXTURE_IMAGE_FRAC)                        \
}

/*
 *  4-bit load block.  Allows tmem and render tile to be specified.  Useful when
 *  loading multiple tiles.  The S means odd lines are already word swapped.
 */
#define gDPLoadMultiBlock_4bS(pkt, timg, tmem, rtile, fmt, width, height, \
        pal, cms, cmt, masks, maskt, shifts, shiftt)                      \
{                                                                         \
    gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg);                  \
    gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0,         \
            cmt, maskt, shiftt, cms, masks, shifts);                      \
    gDPLoadSync(pkt);                                                     \
    gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0,                                \
            (((width)*(height)+3)>>2)-1, 0 );                             \
    gDPPipeSync(pkt);                                                     \
    gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), tmem,        \
            rtile, pal, cmt, maskt, shiftt, cms, masks,                   \
            shifts);                                                      \
    gDPSetTileSize(pkt, rtile, 0, 0,                                      \
            ((width)-1) << G_TEXTURE_IMAGE_FRAC,                          \
            ((height)-1) << G_TEXTURE_IMAGE_FRAC)                         \
}


#define _gDPLoadTextureBlock_4b(pkt, timg, tmem, fmt, width, height, \
        pal, cms, cmt, masks, maskt, shifts, shiftt)                 \
{                                                                    \
    gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg);             \
    gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0,    \
            cmt, maskt, shiftt, cms, masks, shifts);                 \
    gDPLoadSync(pkt);                                                \
    gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0,                           \
            (((width)*(height)+3)>>2)-1,                             \
            CALC_DXT_4b(width));                                     \
    gDPPipeSync(pkt);                                                \
    gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), tmem,   \
            G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,    \
            shifts);                                                 \
    gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0,                       \
            ((width)-1) << G_TEXTURE_IMAGE_FRAC,                     \
            ((height)-1) << G_TEXTURE_IMAGE_FRAC)                    \
}

#define gsDPLoadTextureBlock_4b(timg, fmt, width, height,                             \
        pal, cms, cmt, masks, maskt, shifts, shiftt)                                  \
                                                                                      \
        gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg),                              \
        gsDPSetTile(fmt, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0 , cmt,                  \
                maskt, shiftt, cms, masks, shifts),                                   \
                gsDPLoadSync(),                                                       \
                gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width)*(height)+3)>>2)-1,       \
                        CALC_DXT_4b(width)),                                          \
                        gsDPPipeSync(),                                               \
                        gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), 0,       \
                                G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \
                                shifts),                                              \
                                gsDPSetTileSize(G_TX_RENDERTILE, 0, 0,                \
                                        ((width)-1) << G_TEXTURE_IMAGE_FRAC,          \
                                        ((height)-1) << G_TEXTURE_IMAGE_FRAC)

#define gsDPLoadTextureBlock_4bS(timg, fmt, width, height,                         \
        pal, cms, cmt, masks, maskt, shifts, shiftt)                               \
                                                                                   \
        gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg),                           \
        gsDPSetTile(fmt, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0 , cmt,               \
                maskt, shiftt, cms, masks, shifts),                                \
                gsDPLoadSync(),                                                    \
                gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width)*(height)+3)>>2)-1,0), \
                gsDPPipeSync(),                                                    \
                gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), 0,            \
                        G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,      \
                        shifts),                                                   \
                        gsDPSetTileSize(G_TX_RENDERTILE, 0, 0,                     \
                                ((width)-1) << G_TEXTURE_IMAGE_FRAC,               \
                                ((height)-1) << G_TEXTURE_IMAGE_FRAC)

/*
 *  4-bit load block.  Allows tmem address and render tile to be specified.
 *  Useful when loading multiple tiles.
 */
#define gsDPLoadMultiBlock_4b(timg, tmem, rtile, fmt, width, height,               \
        pal, cms, cmt, masks, maskt, shifts, shiftt)                               \
                                                                                   \
        gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg),                           \
        gsDPSetTile(fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0 , cmt,            \
                maskt, shiftt, cms, masks, shifts),                                \
                gsDPLoadSync(),                                                    \
                gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width)*(height)+3)>>2)-1,    \
                        CALC_DXT_4b(width)),                                       \
                        gsDPPipeSync(),                                            \
                        gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), tmem, \
                                rtile, pal, cmt, maskt, shiftt, cms, masks,        \
                                shifts),                                           \
                                gsDPSetTileSize(rtile, 0, 0,                       \
                                        ((width)-1) << G_TEXTURE_IMAGE_FRAC,       \
                                        ((height)-1) << G_TEXTURE_IMAGE_FRAC)


/*
 *  4-bit load block.  Allows tmem address and render tile to be specified.
 *  Useful when loading multiple tiles.  S means odd lines are already swapped.
 */
#define gsDPLoadMultiBlock_4bS(timg, tmem, rtile, fmt, width, height,              \
        pal, cms, cmt, masks, maskt, shifts, shiftt)                               \
                                                                                   \
        gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg),                           \
        gsDPSetTile(fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0 , cmt,            \
                maskt, shiftt, cms, masks, shifts),                                \
                gsDPLoadSync(),                                                    \
                gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width)*(height)+3)>>2)-1,0), \
                gsDPPipeSync(),                                                    \
                gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), tmem,         \
                        rtile, pal, cmt, maskt, shiftt, cms, masks,                \
                        shifts),                                                   \
                        gsDPSetTileSize(rtile, 0, 0,                               \
                                ((width)-1) << G_TEXTURE_IMAGE_FRAC,               \
                                ((height)-1) << G_TEXTURE_IMAGE_FRAC)


/*
 *  Allows tmem address to be specified
 */
#define _gsDPLoadTextureBlock_4b(timg, tmem, fmt, width, height,                      \
        pal, cms, cmt, masks, maskt, shifts, shiftt)                                  \
                                                                                      \
        gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg),                              \
        gsDPSetTile(fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0 , cmt,               \
                maskt, shiftt, cms, masks, shifts),                                   \
                gsDPLoadSync(),                                                       \
                gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width)*(height)+3)>>2)-1,       \
                        CALC_DXT_4b(width)),                                          \
                        gsDPPipeSync(),                                               \
                        gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), tmem,    \
                                G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \
                                shifts),                                              \
                                gsDPSetTileSize(G_TX_RENDERTILE, 0, 0,                \
                                        ((width)-1) << G_TEXTURE_IMAGE_FRAC,          \
                                        ((height)-1) << G_TEXTURE_IMAGE_FRAC)

#define gDPLoadTextureTile(pkt, timg, fmt, siz, width, height,    \
        uls, ult, lrs, lrt, pal,                                  \
        cms, cmt, masks, maskt, shifts, shiftt)                   \
{                                                                 \
    gDPSetTextureImage(pkt, fmt, siz, width, timg);               \
    gDPSetTile(pkt, fmt, siz,                                     \
            (((((lrs)-(uls)+1) * siz##_TILE_BYTES)+7)>>3), 0,     \
            G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks,    \
            shifts);                                              \
    gDPLoadSync(pkt);                                             \
    gDPLoadTile(pkt, G_TX_LOADTILE,                               \
            (uls)<<G_TEXTURE_IMAGE_FRAC,                          \
            (ult)<<G_TEXTURE_IMAGE_FRAC,                          \
            (lrs)<<G_TEXTURE_IMAGE_FRAC,                          \
            (lrt)<<G_TEXTURE_IMAGE_FRAC);                         \
    gDPPipeSync(pkt);                                             \
    gDPSetTile(pkt, fmt, siz,                                     \
            (((((lrs)-(uls)+1) * siz##_LINE_BYTES)+7)>>3), 0,     \
            G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \
            shifts);                                              \
    gDPSetTileSize(pkt, G_TX_RENDERTILE,                          \
            (uls)<<G_TEXTURE_IMAGE_FRAC,                          \
            (ult)<<G_TEXTURE_IMAGE_FRAC,                          \
            (lrs)<<G_TEXTURE_IMAGE_FRAC,                          \
            (lrt)<<G_TEXTURE_IMAGE_FRAC)                          \
}

/*
 *  Load texture tile.  Allows tmem address and render tile to be specified.
 *  Useful for loading multiple tiles.
 */
#define gDPLoadMultiTile(pkt, timg, tmem, rtile, fmt, siz, width, height, \
        uls, ult, lrs, lrt, pal,                                          \
        cms, cmt, masks, maskt, shifts, shiftt)                           \
{                                                                         \
    gDPSetTextureImage(pkt, fmt, siz, width, timg);                       \
    gDPSetTile(pkt, fmt, siz,                                             \
            (((((lrs)-(uls)+1) * siz##_TILE_BYTES)+7)>>3), tmem,          \
            G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks,            \
            shifts);                                                      \
    gDPLoadSync(pkt);                                                     \
    gDPLoadTile(pkt, G_TX_LOADTILE,                                       \
            (uls)<<G_TEXTURE_IMAGE_FRAC,                                  \
            (ult)<<G_TEXTURE_IMAGE_FRAC,                                  \
            (lrs)<<G_TEXTURE_IMAGE_FRAC,                                  \
            (lrt)<<G_TEXTURE_IMAGE_FRAC);                                 \
    gDPPipeSync(pkt);                                                     \
    gDPSetTile(pkt, fmt, siz,                                             \
            (((((lrs)-(uls)+1) * siz##_LINE_BYTES)+7)>>3), tmem,          \
            rtile, pal, cmt, maskt, shiftt, cms, masks,                   \
            shifts);                                                      \
    gDPSetTileSize(pkt, rtile,                                            \
            (uls)<<G_TEXTURE_IMAGE_FRAC,                                  \
            (ult)<<G_TEXTURE_IMAGE_FRAC,                                  \
            (lrs)<<G_TEXTURE_IMAGE_FRAC,                                  \
            (lrt)<<G_TEXTURE_IMAGE_FRAC)                                  \
}

#define gsDPLoadTextureTile(timg, fmt, siz, width, height,                            \
        uls, ult, lrs, lrt, pal,                                                      \
        cms, cmt, masks, maskt, shifts, shiftt)                                       \
                                                                                      \
        gsDPSetTextureImage(fmt, siz, width, timg),                                   \
        gsDPSetTile(fmt, siz,                                                         \
                (((((lrs)-(uls)+1) * siz##_TILE_BYTES)+7)>>3), 0,                     \
                G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks,                    \
                shifts),                                                              \
                gsDPLoadSync(),                                                       \
                gsDPLoadTile(G_TX_LOADTILE,                                           \
                        (uls)<<G_TEXTURE_IMAGE_FRAC,                                  \
                        (ult)<<G_TEXTURE_IMAGE_FRAC,                                  \
                        (lrs)<<G_TEXTURE_IMAGE_FRAC,                                  \
                        (lrt)<<G_TEXTURE_IMAGE_FRAC),                                 \
                        gsDPPipeSync(),                                               \
                        gsDPSetTile(fmt, siz,                                         \
                                (((((lrs)-(uls)+1) * siz##_LINE_BYTES)+7)>>3), 0,     \
                                G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \
                                shifts),                                              \
                                gsDPSetTileSize(G_TX_RENDERTILE,                      \
                                        (uls)<<G_TEXTURE_IMAGE_FRAC,                  \
                                        (ult)<<G_TEXTURE_IMAGE_FRAC,                  \
                                        (lrs)<<G_TEXTURE_IMAGE_FRAC,                  \
                                        (lrt)<<G_TEXTURE_IMAGE_FRAC)

/*
 *  Load texture tile.  Allows tmem address and render tile to be specified.
 *  Useful for loading multiple tiles.
 */
#define gsDPLoadMultiTile(timg, tmem, rtile, fmt, siz, width, height,             \
        uls, ult, lrs, lrt, pal,                                                  \
        cms, cmt, masks, maskt, shifts, shiftt)                                   \
                                                                                  \
        gsDPSetTextureImage(fmt, siz, width, timg),                               \
        gsDPSetTile(fmt, siz,                                                     \
                (((((lrs)-(uls)+1) * siz##_TILE_BYTES)+7)>>3),                    \
                tmem, G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms,                 \
                masks, shifts),                                                   \
                gsDPLoadSync(),                                                   \
                gsDPLoadTile(G_TX_LOADTILE,                                       \
                        (uls)<<G_TEXTURE_IMAGE_FRAC,                              \
                        (ult)<<G_TEXTURE_IMAGE_FRAC,                              \
                        (lrs)<<G_TEXTURE_IMAGE_FRAC,                              \
                        (lrt)<<G_TEXTURE_IMAGE_FRAC),                             \
                        gsDPPipeSync(),                                           \
                        gsDPSetTile(fmt, siz,                                     \
                                (((((lrs)-(uls)+1) * siz##_LINE_BYTES)+7)>>3),    \
                                tmem, rtile, pal, cmt, maskt, shiftt, cms, masks, \
                                shifts),                                          \
                                gsDPSetTileSize(rtile,                            \
                                        (uls)<<G_TEXTURE_IMAGE_FRAC,              \
                                        (ult)<<G_TEXTURE_IMAGE_FRAC,              \
                                        (lrs)<<G_TEXTURE_IMAGE_FRAC,              \
                                        (lrt)<<G_TEXTURE_IMAGE_FRAC)

#define gDPLoadTextureTile_4b(pkt, timg, fmt, width, height,       \
        uls, ult, lrs, lrt, pal,                                   \
        cms, cmt, masks, maskt, shifts, shiftt)                    \
{                                                                  \
    gDPSetTextureImage(pkt, fmt, G_IM_SIZ_8b, ((width)>>1), timg); \
    gDPSetTile(pkt, fmt, G_IM_SIZ_8b,                              \
            (((((lrs)-(uls)+1)>>1)+7)>>3), 0,                      \
            G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks,     \
            shifts);                                               \
    gDPLoadSync(pkt);                                              \
    gDPLoadTile(pkt, G_TX_LOADTILE,                                \
            (uls)<<(G_TEXTURE_IMAGE_FRAC-1),                       \
            (ult)<<(G_TEXTURE_IMAGE_FRAC),                         \
            (lrs)<<(G_TEXTURE_IMAGE_FRAC-1),                       \
            (lrt)<<(G_TEXTURE_IMAGE_FRAC));                        \
    gDPPipeSync(pkt);                                              \
    gDPSetTile(pkt, fmt, G_IM_SIZ_4b,                              \
            (((((lrs)-(uls)+1)>>1)+7)>>3), 0,                      \
            G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms,         \
            masks, shifts);                                        \
    gDPSetTileSize(pkt, G_TX_RENDERTILE,                           \
            (uls)<<G_TEXTURE_IMAGE_FRAC,                           \
            (ult)<<G_TEXTURE_IMAGE_FRAC,                           \
            (lrs)<<G_TEXTURE_IMAGE_FRAC,                           \
            (lrt)<<G_TEXTURE_IMAGE_FRAC)                           \
}

/*
 *  Load texture tile.  Allows tmem address and render tile to be specified.
 *  Useful for loading multiple tiles.
 */
#define gDPLoadMultiTile_4b(pkt, timg, tmem, rtile, fmt, width, height, \
        uls, ult, lrs, lrt, pal,                                        \
        cms, cmt, masks, maskt, shifts, shiftt)                         \
{                                                                       \
    gDPSetTextureImage(pkt, fmt, G_IM_SIZ_8b, ((width)>>1), timg);      \
    gDPSetTile(pkt, fmt, G_IM_SIZ_8b,                                   \
            (((((lrs)-(uls)+1)>>1)+7)>>3), tmem,                        \
            G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks,          \
            shifts);                                                    \
    gDPLoadSync(pkt);                                                   \
    gDPLoadTile(pkt, G_TX_LOADTILE,                                     \
            (uls)<<(G_TEXTURE_IMAGE_FRAC-1),                            \
            (ult)<<(G_TEXTURE_IMAGE_FRAC),                              \
            (lrs)<<(G_TEXTURE_IMAGE_FRAC-1),                            \
            (lrt)<<(G_TEXTURE_IMAGE_FRAC));                             \
    gDPPipeSync(pkt);                                                   \
    gDPSetTile(pkt, fmt, G_IM_SIZ_4b,                                   \
            (((((lrs)-(uls)+1)>>1)+7)>>3), tmem,                        \
            rtile, pal, cmt, maskt, shiftt, cms, masks,                 \
            shifts);                                                    \
    gDPSetTileSize(pkt, rtile,                                          \
            (uls)<<G_TEXTURE_IMAGE_FRAC,                                \
            (ult)<<G_TEXTURE_IMAGE_FRAC,                                \
            (lrs)<<G_TEXTURE_IMAGE_FRAC,                                \
            (lrt)<<G_TEXTURE_IMAGE_FRAC)                                \
}

#define gsDPLoadTextureTile_4b(timg, fmt, width, height,                                \
        uls, ult, lrs, lrt, pal,                                                        \
        cms, cmt, masks, maskt, shifts, shiftt)                                         \
                                                                                        \
        gsDPSetTextureImage(fmt, G_IM_SIZ_8b, ((width)>>1), timg),                      \
        gsDPSetTile(fmt, G_IM_SIZ_8b, (((((lrs)-(uls)+1)>>1)+7)>>3), 0,                 \
                G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks,                      \
                shifts),                                                                \
                gsDPLoadSync(),                                                         \
                gsDPLoadTile(G_TX_LOADTILE,                                             \
                        (uls)<<(G_TEXTURE_IMAGE_FRAC-1),                                \
                        (ult)<<(G_TEXTURE_IMAGE_FRAC),                                  \
                        (lrs)<<(G_TEXTURE_IMAGE_FRAC-1),                                \
                        (lrt)<<(G_TEXTURE_IMAGE_FRAC)),                                 \
                        gsDPPipeSync(),                                                 \
                        gsDPSetTile(fmt, G_IM_SIZ_4b, (((((lrs)-(uls)+1)>>1)+7)>>3), 0, \
                                G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,   \
                                shifts),                                                \
                                gsDPSetTileSize(G_TX_RENDERTILE,                        \
                                        (uls)<<G_TEXTURE_IMAGE_FRAC,                    \
                                        (ult)<<G_TEXTURE_IMAGE_FRAC,                    \
                                        (lrs)<<G_TEXTURE_IMAGE_FRAC,                    \
                                        (lrt)<<G_TEXTURE_IMAGE_FRAC)

/*
 *  Load texture tile.  Allows tmem address and render tile to be specified.
 *  Useful for loading multiple tiles.
 */
#define gsDPLoadMultiTile_4b(timg, tmem, rtile, fmt, width, height,                  \
        uls, ult, lrs, lrt, pal,                                                     \
        cms, cmt, masks, maskt, shifts, shiftt)                                      \
                                                                                     \
        gsDPSetTextureImage(fmt, G_IM_SIZ_8b, ((width)>>1), timg),                   \
        gsDPSetTile(fmt, G_IM_SIZ_8b, (((((lrs)-(uls)+1)>>1)+7)>>3),                 \
                tmem, G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms,                    \
                masks, shifts),                                                      \
                gsDPLoadSync(),                                                      \
                gsDPLoadTile(G_TX_LOADTILE,                                          \
                        (uls)<<(G_TEXTURE_IMAGE_FRAC-1),                             \
                        (ult)<<(G_TEXTURE_IMAGE_FRAC),                               \
                        (lrs)<<(G_TEXTURE_IMAGE_FRAC-1),                             \
                        (lrt)<<(G_TEXTURE_IMAGE_FRAC)),                              \
                        gsDPPipeSync(),                                              \
                        gsDPSetTile(fmt, G_IM_SIZ_4b, (((((lrs)-(uls)+1)>>1)+7)>>3), \
                                tmem, rtile, pal, cmt, maskt, shiftt, cms, masks,    \
                                shifts),                                             \
                                gsDPSetTileSize(rtile,                               \
                                        (uls)<<G_TEXTURE_IMAGE_FRAC,                 \
                                        (ult)<<G_TEXTURE_IMAGE_FRAC,                 \
                                        (lrs)<<G_TEXTURE_IMAGE_FRAC,                 \
                                        (lrt)<<G_TEXTURE_IMAGE_FRAC)

/*
 *  Load a 16-entry palette (for 4-bit CI textures)
 *  Assumes a 16 entry tlut is being loaded, palette # is 0-15
 */
#define gDPLoadTLUT_pal16(pkt, pal, dram)                          \
{                                                                  \
    gDPSetTextureImage(pkt, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram); \
    gDPTileSync(pkt);                                              \
    gDPSetTile(pkt, 0, 0, 0, (256+(((pal)&0xf)*16)),               \
            G_TX_LOADTILE, 0 , 0, 0, 0, 0, 0, 0);                  \
    gDPLoadSync(pkt);                                              \
    gDPLoadTLUTCmd(pkt, G_TX_LOADTILE, 15);                        \
    gDPPipeSync(pkt)                                               \
}


/*
 *  Load a 16-entry palette (for 4-bit CI textures)
 *  Assumes a 16 entry tlut is being loaded, palette # is 0-15
 */
#define gsDPLoadTLUT_pal16(pal, dram)                          \
                                                               \
    gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram), \
    gsDPTileSync(),                                            \
    gsDPSetTile(0, 0, 0, (256+(((pal)&0xf)*16)),               \
            G_TX_LOADTILE, 0 , 0, 0, 0, 0, 0, 0),              \
            gsDPLoadSync(),                                    \
            gsDPLoadTLUTCmd(G_TX_LOADTILE, 15),                \
            gsDPPipeSync()

/*
 *  Load a 256-entry palette (for 8-bit CI textures)
 *  Assumes a 256 entry tlut is being loaded, palette # is not used
 */
#define gDPLoadTLUT_pal256(pkt, dram)                              \
{                                                                  \
    gDPSetTextureImage(pkt, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram); \
    gDPTileSync(pkt);                                              \
    gDPSetTile(pkt, 0, 0, 0, 256,                                  \
            G_TX_LOADTILE, 0 , 0, 0, 0, 0, 0, 0);                  \
    gDPLoadSync(pkt);                                              \
    gDPLoadTLUTCmd(pkt, G_TX_LOADTILE, 255);                       \
    gDPPipeSync(pkt)                                               \
}

#define gsDPLoadTLUT_pal256(dram)                              \
                                                               \
    gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram), \
    gsDPTileSync(),                                            \
    gsDPSetTile(0, 0, 0, 256,                                  \
            G_TX_LOADTILE, 0 , 0, 0, 0, 0, 0, 0),              \
            gsDPLoadSync(),                                    \
            gsDPLoadTLUTCmd(G_TX_LOADTILE, 255),               \
            gsDPPipeSync()

#define gDPLoadTLUT(pkt, count, tmemaddr, dram)                    \
{                                                                  \
    gDPSetTextureImage(pkt, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram); \
    gDPTileSync(pkt);                                              \
    gDPSetTile(pkt, 0, 0, 0, tmemaddr,                             \
            G_TX_LOADTILE, 0 , 0, 0, 0, 0, 0, 0);                  \
    gDPLoadSync(pkt);                                              \
    gDPLoadTLUTCmd(pkt, G_TX_LOADTILE, ((count)-1));               \
    gDPPipeSync(pkt);                                              \
}

#define gsDPLoadTLUT(count, tmemaddr, dram)                    \
                                                               \
    gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram), \
    gsDPTileSync(),                                            \
    gsDPSetTile(0, 0, 0, tmemaddr,                             \
            G_TX_LOADTILE, 0 , 0, 0, 0, 0, 0, 0),              \
            gsDPLoadSync(),                                    \
            gsDPLoadTLUTCmd(G_TX_LOADTILE, ((count)-1)),       \
            gsDPPipeSync()

#define gDPSetScissor(pkt, mode, ulx, uly, lrx, lry) \
{                                                    \
    Gfx *_g = (Gfx *)pkt;                            \
                                                     \
    _g->words.w0 = _SHIFTL(G_SETSCISSOR, 24, 8) |    \
    _SHIFTL((int)((float)(ulx)*4.0F), 12, 12) |      \
    _SHIFTL((int)((float)(uly)*4.0F), 0, 12);        \
    _g->words.w1 = _SHIFTL(mode, 24, 2) |            \
    _SHIFTL((int)((float)(lrx)*4.0F), 12, 12) |      \
    _SHIFTL((int)((float)(lry)*4.0F), 0, 12);        \
}

#define gDPSetScissorFrac(pkt, mode, ulx, uly, lrx, lry) \
{                                                        \
    Gfx *_g = (Gfx *)pkt;                                \
                                                         \
    _g->words.w0 = _SHIFTL(G_SETSCISSOR, 24, 8) |        \
    _SHIFTL((int)((ulx)), 12, 12) |                      \
    _SHIFTL((int)((uly)), 0, 12);                        \
    _g->words.w1 = _SHIFTL(mode, 24, 2) |                \
    _SHIFTL((int)((lrx)), 12, 12) |                      \
    _SHIFTL((int)((lry)), 0, 12);                        \
}

#define gsDPSetScissor(mode, ulx, uly, lrx, lry) \
{                                                \
    _SHIFTL(G_SETSCISSOR, 24, 8) |               \
    _SHIFTL((int)((float)(ulx)*4.0F), 12, 12) |  \
    _SHIFTL((int)((float)(uly)*4.0F), 0, 12),    \
    _SHIFTL(mode, 24, 2) |                       \
    _SHIFTL((int)((float)(lrx)*4.0F), 12, 12) |  \
    _SHIFTL((int)((float)(lry)*4.0F), 0, 12)     \
}

#define gsDPSetScissorFrac(mode, ulx, uly, lrx, lry) \
{                                                    \
    _SHIFTL(G_SETSCISSOR, 24, 8) |                   \
    _SHIFTL((int)((ulx)), 12, 12) |                  \
    _SHIFTL((int)((uly)), 0, 12),                    \
    _SHIFTL(mode, 24, 2) |                           \
    _SHIFTL((int)(lrx), 12, 12) |                    \
    _SHIFTL((int)(lry), 0, 12)                       \
}

/* Fraction never used in fill */
#define gDPFillRectangle(pkt, ulx, uly, lrx, lry)                    \
{                                                                    \
    Gfx *_g = (Gfx *)(pkt);                                          \
                                                                     \
    _g->words.w0 = (_SHIFTL(G_FILLRECT, 24, 8) |                     \
            _SHIFTL((lrx), 14, 10) | _SHIFTL((lry), 2, 10));         \
    _g->words.w1 = (_SHIFTL((ulx), 14, 10) | _SHIFTL((uly), 2, 10)); \
}

#define gsDPFillRectangle(ulx, uly, lrx, lry)              \
{                                                          \
    (_SHIFTL(G_FILLRECT, 24, 8) | _SHIFTL((lrx), 14, 10) | \
     _SHIFTL((lry), 2, 10)),                               \
    (_SHIFTL((ulx), 14, 10) | _SHIFTL((uly), 2, 10))       \
}

/* like gDPFillRectangle but accepts negative arguments */
#define gDPScisFillRectangle(pkt, ulx, uly, lrx, lry) \
{                                                     \
    Gfx *_g = (Gfx *)(pkt);                           \
                                                      \
    _g->words.w0 = (_SHIFTL(G_FILLRECT, 24, 8) |      \
            _SHIFTL(MAX((lrx),0), 14, 10) |           \
            _SHIFTL(MAX((lry),0), 2, 10));            \
    _g->words.w1 = (_SHIFTL(MAX((ulx),0), 14, 10) |   \
            _SHIFTL(MAX((uly),0), 2, 10));            \
}

#define gDPSetConvert(pkt, k0, k1, k2, k3, k4, k5)            \
{                                                             \
    Gfx *_g = (Gfx *)(pkt);                                   \
                                                              \
    _g->words.w0 = (_SHIFTL(G_SETCONVERT, 24, 8) |            \
            _SHIFTL(k0, 13, 9) | _SHIFTL(k1, 4, 9) |          \
            _SHIFTR(k2, 5, 4));                               \
    _g->words.w1 = (_SHIFTL(k2, 27, 5) | _SHIFTL(k3, 18, 9) | \
            _SHIFTL(k4, 9, 9) | _SHIFTL(k5, 0, 9));           \
}

#define gsDPSetConvert(k0, k1, k2, k3, k4, k5)                     \
{                                                                  \
    (_SHIFTL(G_SETCONVERT, 24, 8) |                                \
     _SHIFTL(k0, 13, 9) | _SHIFTL(k1, 4, 9) | _SHIFTL(k2, 5, 4)),  \
    (_SHIFTL(k2, 27, 5) | _SHIFTL(k3, 18, 9) | _SHIFTL(k4, 9, 9) | \
     _SHIFTL(k5, 0, 9))                                            \
}

#define gDPSetKeyR(pkt, cR, sR, wR)                           \
{                                                             \
    Gfx *_g = (Gfx *)(pkt);                                   \
                                                              \
    _g->words.w0 = _SHIFTL(G_SETKEYR, 24, 8);                 \
    _g->words.w1 = (_SHIFTL(wR, 16, 12) | _SHIFTL(cR, 8, 8) | \
            _SHIFTL(sR, 0, 8));                               \
}

#define gsDPSetKeyR(cR, sR, wR)                                 \
{                                                               \
    _SHIFTL(G_SETKEYR, 24, 8),                                  \
    _SHIFTL(wR, 16, 12) | _SHIFTL(cR, 8, 8) | _SHIFTL(sR, 0, 8) \
}

#define gDPSetKeyGB(pkt, cG, sG, wG, cB, sB, wB)              \
{                                                             \
    Gfx *_g = (Gfx *)(pkt);                                   \
                                                              \
    _g->words.w0 = (_SHIFTL(G_SETKEYGB, 24, 8) |              \
            _SHIFTL(wG, 12, 12) | _SHIFTL(wB, 0, 12));        \
    _g->words.w1 = (_SHIFTL(cG, 24, 8) | _SHIFTL(sG, 16, 8) | \
            _SHIFTL(cB, 8, 8) | _SHIFTL(sB, 0, 8));           \
}

#define gsDPSetKeyGB(cG, sG, wG, cB, sB, wB)                       \
{                                                                  \
    (_SHIFTL(G_SETKEYGB, 24, 8) | _SHIFTL(wG, 12, 12) |            \
     _SHIFTL(wB, 0, 12)),                                          \
    (_SHIFTL(cG, 24, 8) | _SHIFTL(sG, 16, 8) | _SHIFTL(cB, 8, 8) | \
     _SHIFTL(sB, 0, 8))                                            \
}

#define gDPNoParam(pkt, cmd)            \
{                                       \
    Gfx *_g = (Gfx *)(pkt);             \
                                        \
    _g->words.w0 = _SHIFTL(cmd, 24, 8); \
    _g->words.w1 = 0;                   \
}

#define gsDPNoParam(cmd)   \
{                          \
    _SHIFTL(cmd, 24, 8), 0 \
}

#define gDPParam(pkt, cmd, param)       \
{                                       \
    Gfx *_g = (Gfx *)(pkt);             \
                                        \
    _g->words.w0 = _SHIFTL(cmd, 24, 8); \
    _g->words.w1 = (param);             \
}

#define gsDPParam(cmd, param)    \
{                                \
    _SHIFTL(cmd, 24, 8), (param) \
}

/* Notice that textured rectangles are 128-bit commands, therefore
 * gsDPTextureRectangle() should not be used in display lists
 * under normal circumstances (use gsSPTextureRectangle()).
 * That is also why there is no gDPTextureRectangle() macros.
 */
#define gsDPTextureRectangle(xl, yl, xh, yh, tile, s, t, dsdx, dtdy)   \
{                                                                      \
    (_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(xh, 12, 12) |                 \
     _SHIFTL(yh, 0, 12)),                                              \
    (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12)), \
},                                                                     \
{                                                                      \
    _SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16),                            \
    _SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)                       \
}

#define gDPTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
{                                                                        \
    Gfx *_g = (Gfx *)(pkt);                                              \
    if (pkt);                                                            \
    _g->words.w0 = (_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(xh, 12, 12) |    \
            _SHIFTL(yh, 0, 12));                                         \
    _g->words.w1 = (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) |         \
            _SHIFTL(yl, 0, 12));                                         \
    _g ++;                                                               \
    _g->words.w0 = (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16));             \
    _g->words.w1 = (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16));       \
}

#define gsDPTextureRectangleFlip(xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
{                                                                        \
    (_SHIFTL(G_TEXRECTFLIP, 24, 8) | _SHIFTL(xh, 12, 12) |               \
     _SHIFTL(yh, 0, 12)),                                                \
    (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12)),   \
},                                                                       \
{                                                                        \
    _SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16),                              \
    _SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)                         \
}

#define gDPTextureRectangleFlip(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
{                                                                            \
    Gfx *_g = (Gfx *)(pkt);                                                  \
    if (pkt);                                                                \
    _g->words.w0 = (_SHIFTL(G_TEXRECTFLIP, 24, 8) | _SHIFTL(xh, 12, 12) |    \
            _SHIFTL(yh, 0, 12));                                             \
    _g->words.w1 = (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) |             \
            _SHIFTL(yl, 0, 12));                                             \
    _g ++;                                                                   \
    _g->words.w0 = (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16));                 \
    _g->words.w1 = (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16));           \
}

#define gsSPTextureRectangle(xl, yl, xh, yh, tile, s, t, dsdx, dtdy)        \
    (_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(xh, 12, 12) | _SHIFTL(yh, 0, 12)), \
    (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12)),      \
    gsImmp1(G_RDPHALF_1, (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16))),         \
    gsImmp1(G_RDPHALF_2, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)))

#define gSPTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy)      \
{                                                                             \
    Gfx *_g = (Gfx *)(pkt);                                                   \
                                                                              \
    _g->words.w0 = (_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(xh, 12, 12) |         \
            _SHIFTL(yh, 0, 12));                                              \
    _g->words.w1 = (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) |              \
            _SHIFTL(yl, 0, 12));                                              \
    gImmp1(pkt, G_RDPHALF_1, (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16)));       \
    gImmp1(pkt, G_RDPHALF_2, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16))); \
}

/* like gSPTextureRectangle but accepts negative position arguments */
#define gSPScisTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy)    \
{                                                                               \
    Gfx *_g = (Gfx *)(pkt);                                                     \
                                                                                \
    _g->words.w0 = (_SHIFTL(G_TEXRECT, 24, 8) |                                 \
            _SHIFTL(MAX((s16)(xh),0), 12, 12) |                                 \
            _SHIFTL(MAX((s16)(yh),0), 0, 12));                                  \
    _g->words.w1 = (_SHIFTL((tile), 24, 3) |                                    \
            _SHIFTL(MAX((s16)(xl),0), 12, 12) |                                 \
            _SHIFTL(MAX((s16)(yl),0), 0, 12));                                  \
    gImmp1(pkt, G_RDPHALF_1,                                                    \
            (_SHIFTL(((s) -                                                     \
                      (((s16)(xl) < 0) ?                                        \
                       (((s16)(dsdx) < 0) ?                                     \
                        (MAX((((s16)(xl)*(s16)(dsdx))>>7),0)) :                 \
                        (MIN((((s16)(xl)*(s16)(dsdx))>>7),0))) : 0)),           \
                        16, 16) |                                               \
                        _SHIFTL(((t) -                                          \
                                (((yl) < 0) ?                                   \
                                 (((s16)(dtdy) < 0) ?                           \
                                  (MAX((((s16)(yl)*(s16)(dtdy))>>7),0)) :       \
                                  (MIN((((s16)(yl)*(s16)(dtdy))>>7),0))) : 0)), \
                                  0, 16)));                                     \
    gImmp1(pkt, G_RDPHALF_2, (_SHIFTL((dsdx), 16, 16) |                         \
                _SHIFTL((dtdy), 0, 16)));                                       \
}

#define gsSPTextureRectangleFlip(xl, yl, xh, yh, tile, s, t, dsdx, dtdy)  \
    (_SHIFTL(G_TEXRECTFLIP, 24, 8) | _SHIFTL(xh, 12, 12) |                \
     _SHIFTL(yh, 0, 12)),                                                 \
     (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12)),   \
     gsImmp1(G_RDPHALF_1, (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16))),      \
     gsImmp1(G_RDPHALF_2, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)))

#define gSPTextureRectangleFlip(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy)  \
{                                                                             \
    Gfx *_g = (Gfx *)(pkt);                                                   \
                                                                              \
    _g->words.w0 = (_SHIFTL(G_TEXRECTFLIP, 24, 8) | _SHIFTL(xh, 12, 12) |     \
            _SHIFTL(yh, 0, 12));                                              \
    _g->words.w1 = (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) |              \
            _SHIFTL(yl, 0, 12));                                              \
    gImmp1(pkt, G_RDPHALF_1, (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16)));       \
    gImmp1(pkt, G_RDPHALF_2, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16))); \
}

#define gsDPWord(wordhi, wordlo)                  \
    gsImmp1(G_RDPHALF_1, (unsigned int)(wordhi)), \
    gsImmp1(G_RDPHALF_2, (unsigned int)(wordlo))

#define gDPWord(pkt, wordhi, wordlo)                  \
{                                                     \
    Gfx *_g = (Gfx *)(pkt);                           \
                                                      \
    gImmp1(pkt, G_RDPHALF_1, (unsigned int)(wordhi)); \
    gImmp1(pkt, G_RDPHALF_2, (unsigned int)(wordlo)); \
}

#define gDPFullSync(pkt)     gDPNoParam(pkt, G_RDPFULLSYNC)
#define gsDPFullSync()       gsDPNoParam(G_RDPFULLSYNC)
#define gDPTileSync(pkt)     gDPNoParam(pkt, G_RDPTILESYNC)
#define gsDPTileSync()       gsDPNoParam(G_RDPTILESYNC)
#define gDPPipeSync(pkt)     gDPNoParam(pkt, G_RDPPIPESYNC)
#define gsDPPipeSync()       gsDPNoParam(G_RDPPIPESYNC)
#define gDPLoadSync(pkt)     gDPNoParam(pkt, G_RDPLOADSYNC)
#define gsDPLoadSync()       gsDPNoParam(G_RDPLOADSYNC)
#define gDPNoOp(pkt)         gDPNoParam(pkt, G_NOOP)
#define gsDPNoOp()           gsDPNoParam(G_NOOP)
#define gDPNoOpTag(pkt, tag) gDPParam(pkt, G_NOOP, tag)
#define gsDPNoOpTag(tag)     gsDPParam(G_NOOP, tag)

#endif /* _LANGUAGE_C */

#endif /* _GBI_H_ */
